@milaboratories/pl-client 3.2.4 → 3.3.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/core/client.cjs +24 -56
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.d.ts +12 -8
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +26 -58
- package/dist/core/client.js.map +1 -1
- package/dist/core/errors.cjs +20 -0
- package/dist/core/errors.cjs.map +1 -1
- package/dist/core/errors.d.ts +6 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +19 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/final.cjs +6 -5
- package/dist/core/final.cjs.map +1 -1
- package/dist/core/final.d.ts.map +1 -1
- package/dist/core/final.js +7 -6
- package/dist/core/final.js.map +1 -1
- package/dist/core/ll_client.cjs +18 -1
- package/dist/core/ll_client.cjs.map +1 -1
- package/dist/core/ll_client.d.ts +6 -2
- package/dist/core/ll_client.d.ts.map +1 -1
- package/dist/core/ll_client.js +19 -2
- package/dist/core/ll_client.js.map +1 -1
- package/dist/core/transaction.cjs +109 -75
- package/dist/core/transaction.cjs.map +1 -1
- package/dist/core/transaction.d.ts +30 -22
- package/dist/core/transaction.d.ts.map +1 -1
- package/dist/core/transaction.js +111 -76
- package/dist/core/transaction.js.map +1 -1
- package/dist/core/type_conversion.cjs +14 -6
- package/dist/core/type_conversion.cjs.map +1 -1
- package/dist/core/type_conversion.js +14 -6
- package/dist/core/type_conversion.js.map +1 -1
- package/dist/core/types.cjs +77 -17
- package/dist/core/types.cjs.map +1 -1
- package/dist/core/types.d.ts +49 -26
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +66 -14
- package/dist/core/types.js.map +1 -1
- package/dist/core/user_resources.cjs +181 -0
- package/dist/core/user_resources.cjs.map +1 -0
- package/dist/core/user_resources.d.ts +75 -0
- package/dist/core/user_resources.d.ts.map +1 -0
- package/dist/core/user_resources.js +180 -0
- package/dist/core/user_resources.js.map +1 -0
- package/dist/helpers/poll.cjs +4 -4
- package/dist/helpers/poll.cjs.map +1 -1
- package/dist/helpers/poll.d.ts +3 -3
- package/dist/helpers/poll.d.ts.map +1 -1
- package/dist/helpers/poll.js +5 -5
- package/dist/helpers/poll.js.map +1 -1
- package/dist/helpers/tx_helpers.cjs +1 -1
- package/dist/helpers/tx_helpers.cjs.map +1 -1
- package/dist/helpers/tx_helpers.d.ts +3 -3
- package/dist/helpers/tx_helpers.d.ts.map +1 -1
- package/dist/helpers/tx_helpers.js +2 -2
- package/dist/helpers/tx_helpers.js.map +1 -1
- package/dist/index.cjs +16 -5
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +724 -188
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs +34 -9
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts +37 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js +34 -9
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +326 -136
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +724 -188
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs +18 -7
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts +11 -7
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js +18 -7
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs +57 -2
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.d.ts +26 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js +57 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js.map +1 -1
- package/dist/proto-rest/plapi.d.ts +421 -207
- package/dist/proto-rest/plapi.d.ts.map +1 -1
- package/dist/test/test_config.cjs +6 -3
- package/dist/test/test_config.cjs.map +1 -1
- package/dist/test/test_config.d.ts.map +1 -1
- package/dist/test/test_config.js +7 -4
- package/dist/test/test_config.js.map +1 -1
- package/package.json +5 -5
- package/src/core/client.ts +58 -103
- package/src/core/errors.ts +23 -0
- package/src/core/final.ts +16 -6
- package/src/core/ll_client.ts +39 -3
- package/src/core/ll_transaction.test.ts +41 -6
- package/src/core/transaction.ts +176 -86
- package/src/core/type_conversion.ts +24 -9
- package/src/core/types.ts +147 -41
- package/src/core/user_resources.ts +332 -0
- package/src/helpers/poll.ts +15 -8
- package/src/helpers/state_helpers.ts +2 -2
- package/src/helpers/tx_helpers.ts +5 -5
- package/src/index.ts +1 -0
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.ts +61 -14
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +1045 -379
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.ts +33 -18
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.ts +75 -6
- package/src/proto-grpc/google/protobuf/descriptor.ts +5 -2
- package/src/proto-rest/plapi.ts +447 -225
- package/src/test/test_config.ts +8 -5
package/dist/core/types.d.ts
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
|
+
import { Branded } from "@milaboratories/pl-model-common";
|
|
2
|
+
|
|
1
3
|
//#region src/core/types.d.ts
|
|
2
|
-
declare const __resource_id_type__: unique symbol;
|
|
3
|
-
type BrandResourceId<B> = bigint & {
|
|
4
|
-
[__resource_id_type__]: B;
|
|
5
|
-
};
|
|
6
|
-
/** Global resource id */
|
|
7
|
-
type ResourceId = BrandResourceId<"global">;
|
|
8
4
|
/** Null resource id */
|
|
9
|
-
type NullResourceId =
|
|
5
|
+
type NullResourceId = Branded<bigint, "null", "__resource_id__">;
|
|
6
|
+
/** Global resource id */
|
|
7
|
+
type GlobalResourceId = Branded<bigint, "global", "__resource_id__">;
|
|
10
8
|
/** Local resource id */
|
|
11
|
-
type LocalResourceId =
|
|
9
|
+
type LocalResourceId = Branded<bigint, "local", "__resource_id__">;
|
|
12
10
|
/** Any non-null resource id */
|
|
13
|
-
type AnyResourceId =
|
|
14
|
-
/** Any resource id */
|
|
15
|
-
type OptionalResourceId = NullResourceId | ResourceId;
|
|
11
|
+
type AnyResourceId = GlobalResourceId | LocalResourceId;
|
|
16
12
|
/** All possible resource flavours */
|
|
17
|
-
type OptionalAnyResourceId = NullResourceId |
|
|
13
|
+
type OptionalAnyResourceId = NullResourceId | GlobalResourceId | LocalResourceId;
|
|
18
14
|
declare const NullResourceId: NullResourceId;
|
|
19
|
-
declare function isNullResourceId(resourceId: bigint): resourceId is NullResourceId;
|
|
20
|
-
declare function isNotNullResourceId(resourceId: OptionalResourceId): resourceId is ResourceId;
|
|
21
|
-
declare function ensureResourceIdNotNull(resourceId: OptionalResourceId): ResourceId;
|
|
22
15
|
declare function isAnyResourceId(resourceId: bigint): resourceId is AnyResourceId;
|
|
23
16
|
type ResourceKind = "Structural" | "Value";
|
|
24
17
|
type FieldType = "Input" | "Output" | "Service" | "OTW" | "Dynamic" | "MTW";
|
|
@@ -30,15 +23,18 @@ interface ResourceType {
|
|
|
30
23
|
}
|
|
31
24
|
declare function resourceType(name: string, version: string): ResourceType;
|
|
32
25
|
declare function resourceTypeToString(rt: ResourceType): string;
|
|
26
|
+
declare function parseResourceType(str: string): ResourceType;
|
|
33
27
|
declare function resourceTypesEqual(type1: ResourceType, type2: ResourceType): boolean;
|
|
28
|
+
/** Color proof used for resource creation requests (alias for ResourceSignature). */
|
|
29
|
+
type ColorProof = ResourceSignature;
|
|
34
30
|
/** Readonly fields here marks properties of resource that can't change according to pl's state machine. */
|
|
35
31
|
type BasicResourceData = {
|
|
36
|
-
readonly id:
|
|
37
|
-
readonly originalResourceId:
|
|
32
|
+
readonly id: SignedResourceId;
|
|
33
|
+
readonly originalResourceId: OptionalSignedResourceId;
|
|
38
34
|
readonly kind: ResourceKind;
|
|
39
35
|
readonly type: ResourceType;
|
|
40
36
|
readonly data?: Uint8Array;
|
|
41
|
-
readonly error:
|
|
37
|
+
readonly error: OptionalSignedResourceId;
|
|
42
38
|
readonly inputsLocked: boolean;
|
|
43
39
|
readonly outputsLocked: boolean;
|
|
44
40
|
readonly resourceReady: boolean;
|
|
@@ -57,23 +53,50 @@ type FieldData = {
|
|
|
57
53
|
readonly name: string;
|
|
58
54
|
readonly type: FieldType;
|
|
59
55
|
readonly status: FieldStatus;
|
|
60
|
-
readonly value:
|
|
61
|
-
readonly error:
|
|
56
|
+
readonly value: OptionalSignedResourceId;
|
|
57
|
+
readonly error: OptionalSignedResourceId; /** True if value the fields points to is in final state. */
|
|
62
58
|
readonly valueIsFinal: boolean;
|
|
63
59
|
};
|
|
64
60
|
declare const MaxLocalId = 16777215;
|
|
65
61
|
declare const MaxTxId = 4294967295;
|
|
66
62
|
declare function isRootResourceId(id: bigint): boolean;
|
|
67
|
-
declare function isLocalResourceId(id: bigint): id is LocalResourceId;
|
|
63
|
+
declare function isLocalResourceId(id: bigint | string): id is LocalResourceId;
|
|
68
64
|
declare function createLocalResourceId(isRoot: boolean, localCounterValue: number, localTxId: number): LocalResourceId;
|
|
69
|
-
declare function createGlobalResourceId(isRoot: boolean, unmaskedId: bigint):
|
|
65
|
+
declare function createGlobalResourceId(isRoot: boolean, unmaskedId: bigint): GlobalResourceId;
|
|
70
66
|
declare function extractTxId(localResourceId: LocalResourceId): number;
|
|
71
67
|
declare function checkLocalityOfResourceId(resourceId: AnyResourceId, expectedTxId: number): void;
|
|
72
|
-
declare function resourceIdToString(resourceId: OptionalAnyResourceId): string;
|
|
68
|
+
declare function resourceIdToString(resourceId: OptionalAnyResourceId | OptionalSignedResourceId): string;
|
|
73
69
|
declare function resourceIdFromString(str: string): OptionalAnyResourceId | undefined;
|
|
74
|
-
|
|
75
|
-
declare function bigintToResourceId(resourceId: bigint): ResourceId;
|
|
70
|
+
declare function anyResourceIdToBigint(resourceId: bigint | SignedResourceId): bigint;
|
|
76
71
|
declare function stringifyWithResourceId(object: unknown): string;
|
|
72
|
+
/** Opaque authorization signature attached to a resource. */
|
|
73
|
+
type ResourceSignature = Branded<Uint8Array, "ResourceSignature">;
|
|
74
|
+
/**
|
|
75
|
+
* Signed resource id is "<global ID>|<resource signature hex>", encoded as string
|
|
76
|
+
* (e.g. "NG:0x123EC|1234567890abcdef")
|
|
77
|
+
*/
|
|
78
|
+
type SignedResourceId = Branded<string, "signed", "__signed_resource_id__">;
|
|
79
|
+
type NullSignedResourceId = Branded<string, "null", "__signed_resource_id__">;
|
|
80
|
+
declare const NullSignedResourceId: NullSignedResourceId;
|
|
81
|
+
/** Nullable signed resource ID */
|
|
82
|
+
type OptionalSignedResourceId = NullSignedResourceId | SignedResourceId;
|
|
83
|
+
declare function isNullSignedResourceId(resourceId: bigint | string): resourceId is NullSignedResourceId;
|
|
84
|
+
declare function isNotNullSignedResourceId(resourceId: OptionalSignedResourceId): resourceId is SignedResourceId;
|
|
85
|
+
declare function ensureSignedResourceIdNotNull(resourceId: OptionalSignedResourceId): SignedResourceId;
|
|
86
|
+
declare function isSignedResourceId(resourceId: bigint | string): resourceId is SignedResourceId;
|
|
87
|
+
/** Encode resource signature to base64url for embedding in URL-based handles. */
|
|
88
|
+
declare function signatureToBase64Url(sig?: ResourceSignature): string;
|
|
89
|
+
/** Cast raw bytes to a branded ResourceSignature, returning undefined for empty/missing input. */
|
|
90
|
+
declare function toResourceSignature(raw?: Uint8Array): ResourceSignature;
|
|
91
|
+
/** Decode base64url-encoded string back to a branded ResourceSignature. */
|
|
92
|
+
declare function base64UrlToSignature(str: string): ResourceSignature;
|
|
93
|
+
/** Converts bigint global resource id and signature to a SignedResourceId string.
|
|
94
|
+
* Format: "<globalIdString>|<signatureHex>" */
|
|
95
|
+
declare function createSignedResourceId(globalId: bigint, signature?: ResourceSignature): SignedResourceId;
|
|
96
|
+
declare function parseSignedResourceId(resourceId: SignedResourceId): {
|
|
97
|
+
globalId: GlobalResourceId;
|
|
98
|
+
signature: ResourceSignature;
|
|
99
|
+
};
|
|
77
100
|
//#endregion
|
|
78
|
-
export { AnyResourceId, BasicResourceData, FieldData, FieldStatus, FieldType, FutureFieldType, LocalResourceId, MaxLocalId, MaxTxId, NullResourceId, OptionalAnyResourceId,
|
|
101
|
+
export { AnyResourceId, BasicResourceData, ColorProof, FieldData, FieldStatus, FieldType, FutureFieldType, GlobalResourceId, LocalResourceId, MaxLocalId, MaxTxId, NullResourceId, NullSignedResourceId, OptionalAnyResourceId, OptionalSignedResourceId, ResourceData, ResourceKind, ResourceSignature, ResourceType, SignedResourceId, anyResourceIdToBigint, base64UrlToSignature, checkLocalityOfResourceId, createGlobalResourceId, createLocalResourceId, createSignedResourceId, ensureSignedResourceIdNotNull, extractBasicResourceData, extractTxId, getField, isAnyResourceId, isLocalResourceId, isNotNullSignedResourceId, isNullSignedResourceId, isRootResourceId, isSignedResourceId, jsonToData, parseResourceType, parseSignedResourceId, resDataToJson, resourceIdFromString, resourceIdToString, resourceType, resourceTypeToString, resourceTypesEqual, signatureToBase64Url, stringifyWithResourceId, toResourceSignature };
|
|
79
102
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/core/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/core/types.ts"],"mappings":"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"}
|
package/dist/core/types.js
CHANGED
|
@@ -4,13 +4,6 @@ const NullResourceId = 0n;
|
|
|
4
4
|
function isNullResourceId(resourceId) {
|
|
5
5
|
return resourceId === NullResourceId;
|
|
6
6
|
}
|
|
7
|
-
function isNotNullResourceId(resourceId) {
|
|
8
|
-
return resourceId !== NullResourceId;
|
|
9
|
-
}
|
|
10
|
-
function ensureResourceIdNotNull(resourceId) {
|
|
11
|
-
if (!isNotNullResourceId(resourceId)) throw new Error("null resource id");
|
|
12
|
-
return resourceId;
|
|
13
|
-
}
|
|
14
7
|
function isAnyResourceId(resourceId) {
|
|
15
8
|
return resourceId !== 0n;
|
|
16
9
|
}
|
|
@@ -23,6 +16,13 @@ function resourceType(name, version) {
|
|
|
23
16
|
function resourceTypeToString(rt) {
|
|
24
17
|
return `${rt.name}:${rt.version}`;
|
|
25
18
|
}
|
|
19
|
+
function parseResourceType(str) {
|
|
20
|
+
const [name, version] = str.split(":");
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
version
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
26
|
function resourceTypesEqual(type1, type2) {
|
|
27
27
|
return type1.name === type2.name && type1.version === type2.version;
|
|
28
28
|
}
|
|
@@ -59,6 +59,7 @@ function isRootResourceId(id) {
|
|
|
59
59
|
return (id & ResourceIdRootMask) !== 0n;
|
|
60
60
|
}
|
|
61
61
|
function isLocalResourceId(id) {
|
|
62
|
+
if (typeof id === "string") return false;
|
|
62
63
|
return (id & ResourceIdLocalMask) !== 0n;
|
|
63
64
|
}
|
|
64
65
|
function createLocalResourceId(isRoot, localCounterValue, localTxId) {
|
|
@@ -76,6 +77,8 @@ function checkLocalityOfResourceId(resourceId, expectedTxId) {
|
|
|
76
77
|
if (extractTxId(resourceId) !== expectedTxId) throw Error("local id from another transaction, globalize id before leaking it from the transaction");
|
|
77
78
|
}
|
|
78
79
|
function resourceIdToString(resourceId) {
|
|
80
|
+
if (isSignedResourceId(resourceId)) resourceId = anyResourceIdToBigint(resourceId);
|
|
81
|
+
if (isNullSignedResourceId(resourceId)) return "XX:0x0";
|
|
79
82
|
if (isNullResourceId(resourceId)) return "XX:0x0";
|
|
80
83
|
if (isLocalResourceId(resourceId)) return (isRootResourceId(resourceId) ? "R" : "N") + "L:0x" + (LocalIdMask & resourceId).toString(16) + "[0x" + extractTxId(resourceId).toString(16) + "]";
|
|
81
84
|
else return (isRootResourceId(resourceId) ? "R" : "N") + "G:0x" + (NoFlagsIdMask & resourceId).toString(16);
|
|
@@ -89,16 +92,65 @@ function resourceIdFromString(str) {
|
|
|
89
92
|
if (lg === "L") return createLocalResourceId(rn === "R", Number.parseInt(rid, 16), Number.parseInt(txid, 16));
|
|
90
93
|
else return createGlobalResourceId(rn === "R", BigInt("0x" + rid));
|
|
91
94
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (isNullResourceId(resourceId)) throw new Error(`Null resource id.`);
|
|
96
|
-
return resourceId;
|
|
95
|
+
function anyResourceIdToBigint(resourceId) {
|
|
96
|
+
if (typeof resourceId !== "string") return resourceId;
|
|
97
|
+
return parseSignedResourceId(resourceId).globalId;
|
|
97
98
|
}
|
|
98
99
|
function stringifyWithResourceId(object) {
|
|
99
|
-
return JSON.stringify(object, (key, value) =>
|
|
100
|
+
return JSON.stringify(object, (key, value) => {
|
|
101
|
+
if (typeof value === "bigint") return resourceIdToString(value);
|
|
102
|
+
if (isSignedResourceId(value)) return resourceIdToString(value);
|
|
103
|
+
return value;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const NullSignedResourceId = "";
|
|
107
|
+
function isNullSignedResourceId(resourceId) {
|
|
108
|
+
return resourceId === "";
|
|
109
|
+
}
|
|
110
|
+
function isNotNullSignedResourceId(resourceId) {
|
|
111
|
+
return resourceId !== "";
|
|
112
|
+
}
|
|
113
|
+
function ensureSignedResourceIdNotNull(resourceId) {
|
|
114
|
+
if (!isNotNullSignedResourceId(resourceId)) throw new Error("null resource id");
|
|
115
|
+
return resourceId;
|
|
116
|
+
}
|
|
117
|
+
function isSignedResourceId(resourceId) {
|
|
118
|
+
return typeof resourceId === "string" && resourceId.includes("|");
|
|
119
|
+
}
|
|
120
|
+
/** Encode resource signature to base64url for embedding in URL-based handles. */
|
|
121
|
+
function signatureToBase64Url(sig) {
|
|
122
|
+
return sig && sig.length > 0 ? Buffer.from(sig).toString("base64url") : "";
|
|
123
|
+
}
|
|
124
|
+
/** Cast raw bytes to a branded ResourceSignature, returning undefined for empty/missing input. */
|
|
125
|
+
function toResourceSignature(raw) {
|
|
126
|
+
return raw && raw.length > 0 ? raw : new Uint8Array(0);
|
|
127
|
+
}
|
|
128
|
+
/** Decode base64url-encoded string back to a branded ResourceSignature. */
|
|
129
|
+
function base64UrlToSignature(str) {
|
|
130
|
+
return toResourceSignature(Buffer.from(str, "base64url"));
|
|
131
|
+
}
|
|
132
|
+
/** Converts bigint global resource id and signature to a SignedResourceId string.
|
|
133
|
+
* Format: "<globalIdString>|<signatureHex>" */
|
|
134
|
+
function createSignedResourceId(globalId, signature) {
|
|
135
|
+
if (isLocalResourceId(globalId)) throw new Error(`Local resource id: ${resourceIdToString(globalId)}`);
|
|
136
|
+
if (isNullResourceId(globalId)) throw new Error(`Null resource id.`);
|
|
137
|
+
const sigHex = signature ? Buffer.from(signature).toString("hex") : "";
|
|
138
|
+
return `${String(globalId)}|${sigHex}`;
|
|
139
|
+
}
|
|
140
|
+
function parseSignedResourceId(resourceId) {
|
|
141
|
+
if (typeof resourceId !== "string") throw new Error(`Not a signed resource id: ${resourceId}`);
|
|
142
|
+
const pipeIdx = resourceId.indexOf("|");
|
|
143
|
+
if (pipeIdx < 0) throw new Error(`Malformed signed resource id (no '|'): ${resourceId}`);
|
|
144
|
+
const globalIdStr = resourceId.substring(0, pipeIdx);
|
|
145
|
+
const signatureHex = resourceId.substring(pipeIdx + 1);
|
|
146
|
+
const globalId = BigInt(globalIdStr);
|
|
147
|
+
if (isNullSignedResourceId(globalId) || isLocalResourceId(globalId)) throw new Error(`Invalid global id portion in signed resource id: ${globalIdStr}`);
|
|
148
|
+
return {
|
|
149
|
+
globalId,
|
|
150
|
+
signature: signatureHex.length > 0 ? Buffer.from(signatureHex, "hex") : new Uint8Array(0)
|
|
151
|
+
};
|
|
100
152
|
}
|
|
101
153
|
//#endregion
|
|
102
|
-
export { MaxLocalId, MaxTxId, NullResourceId,
|
|
154
|
+
export { MaxLocalId, MaxTxId, NullResourceId, NullSignedResourceId, anyResourceIdToBigint, base64UrlToSignature, checkLocalityOfResourceId, createGlobalResourceId, createLocalResourceId, createSignedResourceId, ensureSignedResourceIdNotNull, extractBasicResourceData, extractTxId, getField, isAnyResourceId, isLocalResourceId, isNotNullSignedResourceId, isNullSignedResourceId, isRootResourceId, isSignedResourceId, jsonToData, parseResourceType, parseSignedResourceId, resDataToJson, resourceIdFromString, resourceIdToString, resourceType, resourceTypeToString, resourceTypesEqual, signatureToBase64Url, stringifyWithResourceId, toResourceSignature };
|
|
103
155
|
|
|
104
156
|
//# sourceMappingURL=types.js.map
|
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/core/types.ts"],"sourcesContent":["import { cachedDeserialize, notEmpty } from \"@milaboratories/ts-helpers\";\n\n// more details here: https://egghead.io/blog/using-branded-types-in-typescript\ndeclare const __resource_id_type__: unique symbol;\ntype BrandResourceId<B> = bigint & { [__resource_id_type__]: B };\n\n/** Global resource id */\nexport type ResourceId = BrandResourceId<\"global\">;\n\n/** Null resource id */\nexport type NullResourceId = BrandResourceId<\"null\">;\n\n/** Local resource id */\nexport type LocalResourceId = BrandResourceId<\"local\">;\n\n/** Any non-null resource id */\nexport type AnyResourceId = ResourceId | LocalResourceId;\n\n/** Any resource id */\nexport type OptionalResourceId = NullResourceId | ResourceId;\n\n/** All possible resource flavours */\nexport type OptionalAnyResourceId = NullResourceId | ResourceId | LocalResourceId;\n\nexport const NullResourceId = 0n as NullResourceId;\n\nexport function isNullResourceId(resourceId: bigint): resourceId is NullResourceId {\n return resourceId === NullResourceId;\n}\n\nexport function isNotNullResourceId(resourceId: OptionalResourceId): resourceId is ResourceId {\n return resourceId !== NullResourceId;\n}\n\nexport function ensureResourceIdNotNull(resourceId: OptionalResourceId): ResourceId {\n if (!isNotNullResourceId(resourceId)) throw new Error(\"null resource id\");\n return resourceId;\n}\n\nexport function isAnyResourceId(resourceId: bigint): resourceId is AnyResourceId {\n return resourceId !== 0n;\n}\n\n// see local / global resource logic below...\n\nexport type ResourceKind = \"Structural\" | \"Value\";\n\nexport type FieldType = \"Input\" | \"Output\" | \"Service\" | \"OTW\" | \"Dynamic\" | \"MTW\";\n\nexport type FutureFieldType = \"Output\" | \"Input\" | \"Service\";\n\nexport type FieldStatus = \"Empty\" | \"Assigned\" | \"Resolved\";\n\nexport interface ResourceType {\n readonly name: string;\n readonly version: string;\n}\n\nexport function resourceType(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport function resourceTypeToString(rt: ResourceType): string {\n return `${rt.name}:${rt.version}`;\n}\n\nexport function resourceTypesEqual(type1: ResourceType, type2: ResourceType): boolean {\n return type1.name === type2.name && type1.version === type2.version;\n}\n\n/** Readonly fields here marks properties of resource that can't change according to pl's state machine. */\nexport type BasicResourceData = {\n readonly id: ResourceId;\n readonly originalResourceId: OptionalResourceId;\n\n readonly kind: ResourceKind;\n readonly type: ResourceType;\n\n readonly data?: Uint8Array;\n\n readonly error: OptionalResourceId;\n\n readonly inputsLocked: boolean;\n readonly outputsLocked: boolean;\n readonly resourceReady: boolean;\n\n /** This value is derived from resource state by the server and can be used as\n * a robust criteria to determine resource is in final state. */\n readonly final: boolean;\n};\n\nexport function extractBasicResourceData(rd: ResourceData): BasicResourceData {\n const {\n id,\n originalResourceId,\n kind,\n type,\n data,\n error,\n inputsLocked,\n outputsLocked,\n resourceReady,\n final,\n } = rd;\n return {\n id,\n originalResourceId,\n kind,\n type,\n data,\n error,\n inputsLocked,\n outputsLocked,\n resourceReady,\n final,\n };\n}\n\nexport const jsonToData = (data: unknown) => Buffer.from(JSON.stringify(data));\n\nexport const resDataToJson = (res: ResourceData) => cachedDeserialize(notEmpty(res.data));\n\nexport type ResourceData = BasicResourceData & {\n readonly fields: FieldData[];\n};\n\nexport function getField(r: ResourceData, name: string): FieldData {\n return notEmpty(r.fields.find((f) => f.name === name));\n}\n\nexport type FieldData = {\n readonly name: string;\n readonly type: FieldType;\n readonly status: FieldStatus;\n readonly value: OptionalResourceId;\n readonly error: OptionalResourceId;\n\n /** True if value the fields points to is in final state. */\n readonly valueIsFinal: boolean;\n};\n\n//\n// Local / Global ResourceId arithmetics\n//\n\n// Note: txId and other numerical values are made numbers but not bigint intentionally,\n// after implementing security model based on signed resource ids this will make\n// much more sense\n\nconst ResourceIdRootMask = 1n << 63n;\nconst ResourceIdLocalMask = 1n << 62n;\nconst NoFlagsIdMask = 0x3fffffffffffffffn;\nconst LocalResourceIdTxIdOffset = 24n;\nexport const MaxLocalId = 0xffffff;\nexport const MaxTxId = 0xffffffff;\n/** Mask valid after applying shift */\nconst TxIdMask = BigInt(MaxTxId);\nconst LocalIdMask = BigInt(MaxLocalId);\n\n// /** Basically removes embedded tx id */\n// const LocalIdCleanMask = 0xFF00000000FFFFFFn;\n\nexport function isRootResourceId(id: bigint) {\n return (id & ResourceIdRootMask) !== 0n;\n}\n\nexport function isLocalResourceId(id: bigint): id is LocalResourceId {\n return (id & ResourceIdLocalMask) !== 0n;\n}\n\nexport function createLocalResourceId(\n isRoot: boolean,\n localCounterValue: number,\n localTxId: number,\n): LocalResourceId {\n if (\n localCounterValue > MaxLocalId ||\n localTxId > MaxTxId ||\n localCounterValue < 0 ||\n localTxId <= 0\n )\n throw Error(\"wrong local id or tx id\");\n return ((isRoot ? ResourceIdRootMask : 0n) |\n ResourceIdLocalMask |\n BigInt(localCounterValue) |\n (BigInt(localTxId) << LocalResourceIdTxIdOffset)) as LocalResourceId;\n}\n\nexport function createGlobalResourceId(isRoot: boolean, unmaskedId: bigint): ResourceId {\n return ((isRoot ? ResourceIdRootMask : 0n) | unmaskedId) as ResourceId;\n}\n\nexport function extractTxId(localResourceId: LocalResourceId): number {\n return Number((localResourceId >> LocalResourceIdTxIdOffset) & TxIdMask);\n}\n\nexport function checkLocalityOfResourceId(resourceId: AnyResourceId, expectedTxId: number): void {\n if (!isLocalResourceId(resourceId)) return;\n if (extractTxId(resourceId) !== expectedTxId)\n throw Error(\n \"local id from another transaction, globalize id before leaking it from the transaction\",\n );\n}\n\nexport function resourceIdToString(resourceId: OptionalAnyResourceId): string {\n if (isNullResourceId(resourceId)) return \"XX:0x0\";\n if (isLocalResourceId(resourceId))\n return (\n (isRootResourceId(resourceId) ? \"R\" : \"N\") +\n \"L:0x\" +\n (LocalIdMask & resourceId).toString(16) +\n \"[0x\" +\n extractTxId(resourceId).toString(16) +\n \"]\"\n );\n else\n return (\n (isRootResourceId(resourceId) ? \"R\" : \"N\") +\n \"G:0x\" +\n (NoFlagsIdMask & resourceId).toString(16)\n );\n}\n\nconst resourceIdRegexp =\n /^(?:(?<xx>XX)|(?<rn>[XRN])(?<lg>[XLG])):0x(?<rid>[0-9a-fA-F]+)(?:\\[0x(?<txid>[0-9a-fA-F]+)])?$/;\n\nexport function resourceIdFromString(str: string): OptionalAnyResourceId | undefined {\n const match = str.match(resourceIdRegexp);\n if (match === null) return undefined;\n const { xx, rn, lg, rid, txid } = match.groups!;\n if (xx) return NullResourceId;\n if (lg === \"L\")\n return createLocalResourceId(rn === \"R\", Number.parseInt(rid, 16), Number.parseInt(txid, 16));\n else return createGlobalResourceId(rn === \"R\", BigInt(\"0x\" + rid));\n}\n\n/** Converts bigint to global resource id */\nexport function bigintToResourceId(resourceId: bigint): ResourceId {\n if (isLocalResourceId(resourceId))\n throw new Error(`Local resource id: ${resourceIdToString(resourceId)}`);\n if (isNullResourceId(resourceId)) throw new Error(`Null resource id.`);\n return resourceId as ResourceId;\n}\n\nexport function stringifyWithResourceId(object: unknown): string {\n return JSON.stringify(object, (key, value) =>\n typeof value === \"bigint\" ? resourceIdToString(value as OptionalAnyResourceId) : value,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/core/types.ts"],"sourcesContent":["import type { Branded } from \"@milaboratories/pl-model-common\";\nimport { cachedDeserialize, notEmpty } from \"@milaboratories/ts-helpers\";\n\n/** Null resource id */\nexport type NullResourceId = Branded<bigint, \"null\", \"__resource_id__\">;\n\n/** Global resource id */\nexport type GlobalResourceId = Branded<bigint, \"global\", \"__resource_id__\">;\n\n/** Local resource id */\nexport type LocalResourceId = Branded<bigint, \"local\", \"__resource_id__\">;\n\n/** Any non-null resource id */\nexport type AnyResourceId = GlobalResourceId | LocalResourceId;\n\n/** All possible resource flavours */\nexport type OptionalAnyResourceId = NullResourceId | GlobalResourceId | LocalResourceId;\n\nexport const NullResourceId = 0n as NullResourceId;\n\nfunction isNullResourceId(resourceId: bigint | string): resourceId is NullResourceId {\n return resourceId === NullResourceId;\n}\n\nexport function isAnyResourceId(resourceId: bigint): resourceId is AnyResourceId {\n return resourceId !== 0n;\n}\n\n// see local / global resource logic below...\n\nexport type ResourceKind = \"Structural\" | \"Value\";\n\nexport type FieldType = \"Input\" | \"Output\" | \"Service\" | \"OTW\" | \"Dynamic\" | \"MTW\";\n\nexport type FutureFieldType = \"Output\" | \"Input\" | \"Service\";\n\nexport type FieldStatus = \"Empty\" | \"Assigned\" | \"Resolved\";\n\nexport interface ResourceType {\n readonly name: string;\n readonly version: string;\n}\n\nexport function resourceType(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport function resourceTypeToString(rt: ResourceType): string {\n return `${rt.name}:${rt.version}`;\n}\n\nexport function parseResourceType(str: string): ResourceType {\n const [name, version] = str.split(\":\");\n return { name, version };\n}\n\nexport function resourceTypesEqual(type1: ResourceType, type2: ResourceType): boolean {\n return type1.name === type2.name && type1.version === type2.version;\n}\n\n/** Color proof used for resource creation requests (alias for ResourceSignature). */\nexport type ColorProof = ResourceSignature;\n\n/** Readonly fields here marks properties of resource that can't change according to pl's state machine. */\nexport type BasicResourceData = {\n readonly id: SignedResourceId;\n readonly originalResourceId: OptionalSignedResourceId;\n\n readonly kind: ResourceKind;\n readonly type: ResourceType;\n\n readonly data?: Uint8Array;\n\n readonly error: OptionalSignedResourceId;\n\n readonly inputsLocked: boolean;\n readonly outputsLocked: boolean;\n readonly resourceReady: boolean;\n\n /** This value is derived from resource state by the server and can be used as\n * a robust criteria to determine resource is in final state. */\n readonly final: boolean;\n};\n\nexport function extractBasicResourceData(rd: ResourceData): BasicResourceData {\n const {\n id,\n originalResourceId,\n kind,\n type,\n data,\n error,\n inputsLocked,\n outputsLocked,\n resourceReady,\n final,\n } = rd;\n return {\n id,\n originalResourceId,\n kind,\n type,\n data,\n error,\n inputsLocked,\n outputsLocked,\n resourceReady,\n final,\n };\n}\n\nexport const jsonToData = (data: unknown) => Buffer.from(JSON.stringify(data));\n\nexport const resDataToJson = (res: ResourceData) => cachedDeserialize(notEmpty(res.data));\n\nexport type ResourceData = BasicResourceData & {\n readonly fields: FieldData[];\n};\n\nexport function getField(r: ResourceData, name: string): FieldData {\n return notEmpty(r.fields.find((f) => f.name === name));\n}\n\nexport type FieldData = {\n readonly name: string;\n readonly type: FieldType;\n readonly status: FieldStatus;\n readonly value: OptionalSignedResourceId;\n readonly error: OptionalSignedResourceId;\n\n /** True if value the fields points to is in final state. */\n readonly valueIsFinal: boolean;\n};\n\n//\n// Local / Global ResourceId arithmetics\n//\n\n// Note: txId and other numerical values are made numbers but not bigint intentionally,\n// after implementing security model based on signed resource ids this will make\n// much more sense\n\nconst ResourceIdRootMask = 1n << 63n;\nconst ResourceIdLocalMask = 1n << 62n;\nconst NoFlagsIdMask = 0x3fffffffffffffffn;\nconst LocalResourceIdTxIdOffset = 24n;\nexport const MaxLocalId = 0xffffff;\nexport const MaxTxId = 0xffffffff;\n/** Mask valid after applying shift */\nconst TxIdMask = BigInt(MaxTxId);\nconst LocalIdMask = BigInt(MaxLocalId);\n\n// /** Basically removes embedded tx id */\n// const LocalIdCleanMask = 0xFF00000000FFFFFFn;\n\nexport function isRootResourceId(id: bigint) {\n return (id & ResourceIdRootMask) !== 0n;\n}\n\nexport function isLocalResourceId(id: bigint | string): id is LocalResourceId {\n if (typeof id === \"string\") {\n return false;\n }\n\n return (id & ResourceIdLocalMask) !== 0n;\n}\n\nexport function createLocalResourceId(\n isRoot: boolean,\n localCounterValue: number,\n localTxId: number,\n): LocalResourceId {\n if (\n localCounterValue > MaxLocalId ||\n localTxId > MaxTxId ||\n localCounterValue < 0 ||\n localTxId <= 0\n )\n throw Error(\"wrong local id or tx id\");\n return ((isRoot ? ResourceIdRootMask : 0n) |\n ResourceIdLocalMask |\n BigInt(localCounterValue) |\n (BigInt(localTxId) << LocalResourceIdTxIdOffset)) as LocalResourceId;\n}\n\nexport function createGlobalResourceId(isRoot: boolean, unmaskedId: bigint): GlobalResourceId {\n return ((isRoot ? ResourceIdRootMask : 0n) | unmaskedId) as GlobalResourceId;\n}\n\nexport function extractTxId(localResourceId: LocalResourceId): number {\n return Number((localResourceId >> LocalResourceIdTxIdOffset) & TxIdMask);\n}\n\nexport function checkLocalityOfResourceId(resourceId: AnyResourceId, expectedTxId: number): void {\n if (!isLocalResourceId(resourceId)) return;\n if (extractTxId(resourceId) !== expectedTxId)\n throw Error(\n \"local id from another transaction, globalize id before leaking it from the transaction\",\n );\n}\n\nexport function resourceIdToString(\n resourceId: OptionalAnyResourceId | OptionalSignedResourceId,\n): string {\n if (isSignedResourceId(resourceId)) {\n // Strip signature\n resourceId = anyResourceIdToBigint(resourceId) as GlobalResourceId;\n }\n\n if (isNullSignedResourceId(resourceId)) return \"XX:0x0\";\n if (isNullResourceId(resourceId)) return \"XX:0x0\";\n\n if (isLocalResourceId(resourceId))\n return (\n (isRootResourceId(resourceId) ? \"R\" : \"N\") +\n \"L:0x\" +\n (LocalIdMask & resourceId).toString(16) +\n \"[0x\" +\n extractTxId(resourceId).toString(16) +\n \"]\"\n );\n else\n return (\n (isRootResourceId(resourceId) ? \"R\" : \"N\") +\n \"G:0x\" +\n (NoFlagsIdMask & resourceId).toString(16)\n );\n}\n\nconst resourceIdRegexp =\n /^(?:(?<xx>XX)|(?<rn>[XRN])(?<lg>[XLG])):0x(?<rid>[0-9a-fA-F]+)(?:\\[0x(?<txid>[0-9a-fA-F]+)])?$/;\n\nexport function resourceIdFromString(str: string): OptionalAnyResourceId | undefined {\n const match = str.match(resourceIdRegexp);\n if (match === null) return undefined;\n const { xx, rn, lg, rid, txid } = match.groups!;\n if (xx) return NullResourceId;\n if (lg === \"L\")\n return createLocalResourceId(rn === \"R\", Number.parseInt(rid, 16), Number.parseInt(txid, 16));\n else return createGlobalResourceId(rn === \"R\", BigInt(\"0x\" + rid));\n}\n\nexport function anyResourceIdToBigint(resourceId: bigint | SignedResourceId): bigint {\n if (typeof resourceId !== \"string\") {\n return resourceId;\n }\n\n const parsed = parseSignedResourceId(resourceId);\n return parsed.globalId as bigint;\n}\n\nexport function stringifyWithResourceId(object: unknown): string {\n return JSON.stringify(object, (key, value) => {\n if (typeof value === \"bigint\") return resourceIdToString(value as OptionalAnyResourceId);\n if (isSignedResourceId(value)) return resourceIdToString(value);\n return value;\n });\n}\n\n/** Opaque authorization signature attached to a resource. */\nexport type ResourceSignature = Branded<Uint8Array, \"ResourceSignature\">;\n\n/**\n * Signed resource id is \"<global ID>|<resource signature hex>\", encoded as string\n * (e.g. \"NG:0x123EC|1234567890abcdef\")\n */\nexport type SignedResourceId = Branded<string, \"signed\", \"__signed_resource_id__\">;\n\nexport type NullSignedResourceId = Branded<string, \"null\", \"__signed_resource_id__\">;\n\nexport const NullSignedResourceId = \"\" as NullSignedResourceId;\n\n/** Nullable signed resource ID */\nexport type OptionalSignedResourceId = NullSignedResourceId | SignedResourceId;\n\nexport function isNullSignedResourceId(\n resourceId: bigint | string,\n): resourceId is NullSignedResourceId {\n return resourceId === NullSignedResourceId;\n}\n\nexport function isNotNullSignedResourceId(\n resourceId: OptionalSignedResourceId,\n): resourceId is SignedResourceId {\n // lint-allow-cast\n return resourceId !== NullSignedResourceId;\n}\n\nexport function ensureSignedResourceIdNotNull(\n resourceId: OptionalSignedResourceId,\n): SignedResourceId {\n if (!isNotNullSignedResourceId(resourceId)) throw new Error(\"null resource id\");\n return resourceId;\n}\n\nexport function isSignedResourceId(resourceId: bigint | string): resourceId is SignedResourceId {\n // lint-allow-cast\n return typeof resourceId === \"string\" && resourceId.includes(\"|\");\n}\n\n/** Encode resource signature to base64url for embedding in URL-based handles. */\nexport function signatureToBase64Url(sig?: ResourceSignature): string {\n return sig && sig.length > 0 ? Buffer.from(sig).toString(\"base64url\") : \"\";\n}\n\n/** Cast raw bytes to a branded ResourceSignature, returning undefined for empty/missing input. */\nexport function toResourceSignature(raw?: Uint8Array): ResourceSignature {\n return raw && raw.length > 0\n ? (raw as ResourceSignature)\n : (new Uint8Array(0) as ResourceSignature);\n}\n\n/** Decode base64url-encoded string back to a branded ResourceSignature. */\nexport function base64UrlToSignature(str: string): ResourceSignature {\n return toResourceSignature(Buffer.from(str, \"base64url\"))!;\n}\n\n/** Converts bigint global resource id and signature to a SignedResourceId string.\n * Format: \"<globalIdString>|<signatureHex>\" */\nexport function createSignedResourceId(\n globalId: bigint,\n signature?: ResourceSignature,\n): SignedResourceId {\n if (isLocalResourceId(globalId))\n throw new Error(`Local resource id: ${resourceIdToString(globalId)}`);\n if (isNullResourceId(globalId)) throw new Error(`Null resource id.`);\n\n const sigHex = signature ? Buffer.from(signature).toString(\"hex\") : \"\";\n return `${String(globalId)}|${sigHex}` as SignedResourceId; // lint-allow-cast\n}\n\nexport function parseSignedResourceId(resourceId: SignedResourceId): {\n globalId: GlobalResourceId;\n signature: ResourceSignature;\n} {\n if (typeof resourceId !== \"string\") {\n throw new Error(`Not a signed resource id: ${resourceId}`);\n }\n\n const pipeIdx = resourceId.indexOf(\"|\");\n if (pipeIdx < 0) throw new Error(`Malformed signed resource id (no '|'): ${resourceId}`);\n\n const globalIdStr = resourceId.substring(0, pipeIdx);\n const signatureHex = resourceId.substring(pipeIdx + 1);\n\n const globalId = BigInt(globalIdStr);\n if (isNullSignedResourceId(globalId) || isLocalResourceId(globalId))\n throw new Error(`Invalid global id portion in signed resource id: ${globalIdStr}`);\n\n const signature: ResourceSignature = (\n signatureHex.length > 0 ? Buffer.from(signatureHex, \"hex\") : new Uint8Array(0)\n ) as ResourceSignature;\n\n return { globalId: globalId as GlobalResourceId, signature };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_types = require("./types.cjs");
|
|
3
|
+
const require_errors = require("./errors.cjs");
|
|
4
|
+
const require_transaction = require("./transaction.cjs");
|
|
5
|
+
const require_pl = require("../helpers/pl.cjs");
|
|
6
|
+
let node_crypto = require("node:crypto");
|
|
7
|
+
//#region src/core/user_resources.ts
|
|
8
|
+
const AnonymousClientRoot = "AnonymousRoot";
|
|
9
|
+
const LsStorageTypePrefix = "LS/";
|
|
10
|
+
const LsProviderFieldPrefix = "storage/";
|
|
11
|
+
/**
|
|
12
|
+
* Abstracts user resource discovery with backward compatibility.
|
|
13
|
+
*
|
|
14
|
+
* Detects backend capability on the first getUserRoot() call and remembers
|
|
15
|
+
* the result. Three-tier fallback:
|
|
16
|
+
* 1. getUserRoot RPC (newest, supports doNotCreate)
|
|
17
|
+
* 2. listUserResources RPC (streams all resources, picks userRoot)
|
|
18
|
+
* 3. Named resource lookup/creation via transaction (legacy)
|
|
19
|
+
*/
|
|
20
|
+
var UserResources = class {
|
|
21
|
+
backendCapability;
|
|
22
|
+
constructor(ll, runTx, authUser) {
|
|
23
|
+
this.ll = ll;
|
|
24
|
+
this.runTx = runTx;
|
|
25
|
+
this.authUser = authUser;
|
|
26
|
+
}
|
|
27
|
+
async getUserRoot(opts = {}) {
|
|
28
|
+
if (this.backendCapability === void 0) return await this.detectAndGetUserRoot(opts);
|
|
29
|
+
return await this.getUserRootWith(this.backendCapability, opts);
|
|
30
|
+
}
|
|
31
|
+
async detectAndGetUserRoot(opts = {}) {
|
|
32
|
+
try {
|
|
33
|
+
const root = await this.getUserRootViaRpc(opts);
|
|
34
|
+
this.backendCapability = "getUserRoot";
|
|
35
|
+
return root;
|
|
36
|
+
} catch (err) {
|
|
37
|
+
if (!require_errors.isUnimplementedError(err)) throw err;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const root = await this.getUserRootViaList(opts);
|
|
41
|
+
this.backendCapability = "listUserResources";
|
|
42
|
+
return root;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
if (!require_errors.isUnimplementedError(err)) throw err;
|
|
45
|
+
}
|
|
46
|
+
this.backendCapability = "legacy";
|
|
47
|
+
return await this.getUserRootViaLegacy(opts);
|
|
48
|
+
}
|
|
49
|
+
async getUserRootWith(capability, opts = {}) {
|
|
50
|
+
switch (capability) {
|
|
51
|
+
case "getUserRoot": return await this.getUserRootViaRpc(opts);
|
|
52
|
+
case "listUserResources": return await this.getUserRootViaList(opts);
|
|
53
|
+
case "legacy": return await this.getUserRootViaLegacy(opts);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns all data libraries the user has access to.
|
|
58
|
+
* Always fetches fresh from the server (no caching).
|
|
59
|
+
*/
|
|
60
|
+
async getDataLibraries(opts = {}) {
|
|
61
|
+
if (this.backendCapability === void 0) try {
|
|
62
|
+
const libs = await this.getDataLibrariesViaList(opts);
|
|
63
|
+
this.backendCapability = "listUserResources";
|
|
64
|
+
return libs;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (!require_errors.isUnimplementedError(err)) throw err;
|
|
67
|
+
this.backendCapability = "legacy";
|
|
68
|
+
return await this.getDataLibrariesViaLegacy();
|
|
69
|
+
}
|
|
70
|
+
if (this.backendCapability !== "legacy") return await this.getDataLibrariesViaList(opts);
|
|
71
|
+
return await this.getDataLibrariesViaLegacy();
|
|
72
|
+
}
|
|
73
|
+
async getUserRootViaRpc(opts = {}) {
|
|
74
|
+
const resp = await this.ll.getUserRoot({
|
|
75
|
+
login: opts.login,
|
|
76
|
+
doNotCreate: opts.doNotCreate
|
|
77
|
+
});
|
|
78
|
+
if (resp.userRoot === void 0) {
|
|
79
|
+
if (opts.doNotCreate) return void 0;
|
|
80
|
+
throw new Error("getUserRoot returned no userRoot entry");
|
|
81
|
+
}
|
|
82
|
+
return require_types.createSignedResourceId(resp.userRoot.resourceId, require_types.toResourceSignature(resp.userRoot.resourceSignature));
|
|
83
|
+
}
|
|
84
|
+
async getUserRootViaList(opts = {}) {
|
|
85
|
+
const responses = await this.ll.listUserResources({
|
|
86
|
+
login: opts.login,
|
|
87
|
+
limit: 1
|
|
88
|
+
});
|
|
89
|
+
for (const msg of responses) if (msg.entry.oneofKind === "userRoot") return require_types.createSignedResourceId(msg.entry.userRoot.resourceId, require_types.toResourceSignature(msg.entry.userRoot.resourceSignature));
|
|
90
|
+
throw new Error("listUserResources returned no userRoot entry");
|
|
91
|
+
}
|
|
92
|
+
async getDataLibrariesViaList(opts = {}) {
|
|
93
|
+
const responses = await this.ll.listUserResources({ login: opts.login });
|
|
94
|
+
const v1Entries = [];
|
|
95
|
+
const v2ResourceIds = [];
|
|
96
|
+
for (const msg of responses) {
|
|
97
|
+
if (msg.entry.oneofKind !== "sharedResource") continue;
|
|
98
|
+
const sr = msg.entry.sharedResource;
|
|
99
|
+
if (!sr.resourceType) continue;
|
|
100
|
+
const typeName = sr.resourceType.name;
|
|
101
|
+
const typeVersion = sr.resourceType.version;
|
|
102
|
+
if (!typeName.startsWith(LsStorageTypePrefix)) continue;
|
|
103
|
+
const rId = require_types.createSignedResourceId(sr.resourceId, require_types.toResourceSignature(sr.resourceSignature));
|
|
104
|
+
const rType = {
|
|
105
|
+
name: typeName,
|
|
106
|
+
version: typeVersion
|
|
107
|
+
};
|
|
108
|
+
if (typeVersion === "2") v2ResourceIds.push({
|
|
109
|
+
resourceId: rId,
|
|
110
|
+
resourceType: rType
|
|
111
|
+
});
|
|
112
|
+
else {
|
|
113
|
+
const storageId = typeName.substring(3);
|
|
114
|
+
v1Entries.push({
|
|
115
|
+
storageId,
|
|
116
|
+
storageName: storageId,
|
|
117
|
+
resourceId: rId,
|
|
118
|
+
resourceType: rType
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
let v2Entries = [];
|
|
123
|
+
if (v2ResourceIds.length > 0) v2Entries = await this.runTx("ReadLsStorageV2Data", false, "", async (tx) => {
|
|
124
|
+
const entries = [];
|
|
125
|
+
for (const { resourceId, resourceType } of v2ResourceIds) {
|
|
126
|
+
const rd = await tx.getResourceData(resourceId, false);
|
|
127
|
+
if (rd.data) {
|
|
128
|
+
const v2Data = JSON.parse(Buffer.from(rd.data).toString("utf-8"));
|
|
129
|
+
entries.push({
|
|
130
|
+
storageId: v2Data.storageID,
|
|
131
|
+
storageName: v2Data.storageName,
|
|
132
|
+
resourceId,
|
|
133
|
+
resourceType
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return entries;
|
|
138
|
+
});
|
|
139
|
+
const result = /* @__PURE__ */ new Map();
|
|
140
|
+
for (const entry of [...v1Entries, ...v2Entries]) result.set(entry.storageId, entry);
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
async getUserRootViaLegacy(opts = {}) {
|
|
144
|
+
const login = opts.login ?? this.authUser;
|
|
145
|
+
const mainRootName = login === null ? AnonymousClientRoot : (0, node_crypto.createHash)("sha256").update(login).digest("hex");
|
|
146
|
+
return await this.runTx("initialization", true, "", async (tx) => {
|
|
147
|
+
if (await tx.checkResourceNameExists(mainRootName)) return await tx.getResourceByName(mainRootName);
|
|
148
|
+
if (opts.doNotCreateUserRoot) return;
|
|
149
|
+
const mainRoot = tx.createRoot(require_pl.ClientRoot);
|
|
150
|
+
tx.setResourceName(mainRootName, mainRoot);
|
|
151
|
+
await tx.commit();
|
|
152
|
+
return await require_transaction.toGlobalResourceId(mainRoot);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
async getDataLibrariesViaLegacy() {
|
|
156
|
+
return await this.runTx("GetAvailableStorageIds", false, "", async (tx) => {
|
|
157
|
+
const lsProviderId = await tx.getResourceByName("LSProvider");
|
|
158
|
+
const provider = await tx.getResourceData(lsProviderId, true);
|
|
159
|
+
const result = /* @__PURE__ */ new Map();
|
|
160
|
+
for (const field of provider.fields) {
|
|
161
|
+
if (field.type !== "Dynamic" || !require_types.isNotNullSignedResourceId(field.value)) continue;
|
|
162
|
+
if (!field.name.startsWith(LsProviderFieldPrefix)) continue;
|
|
163
|
+
const storageId = field.name.substring(8);
|
|
164
|
+
result.set(storageId, {
|
|
165
|
+
storageId,
|
|
166
|
+
storageName: storageId,
|
|
167
|
+
resourceId: field.value,
|
|
168
|
+
resourceType: {
|
|
169
|
+
name: `${LsStorageTypePrefix}${storageId}`,
|
|
170
|
+
version: "1"
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
//#endregion
|
|
179
|
+
exports.UserResources = UserResources;
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=user_resources.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user_resources.cjs","names":["isUnimplementedError","createSignedResourceId","toResourceSignature","ClientRoot","toGlobalResourceId","isNotNullSignedResourceId"],"sources":["../../src/core/user_resources.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { LLPlClient } from \"./ll_client\";\nimport type { PlTransaction } from \"./transaction\";\nimport { toGlobalResourceId } from \"./transaction\";\nimport type { OptionalSignedResourceId, SignedResourceId, ResourceType } from \"./types\";\nimport {\n createSignedResourceId,\n isNotNullSignedResourceId,\n NullSignedResourceId,\n toResourceSignature,\n} from \"./types\";\nimport { isUnimplementedError } from \"./errors\";\nimport { ClientRoot } from \"../helpers/pl\";\n\nconst AnonymousClientRoot = \"AnonymousRoot\";\nconst LsStorageTypePrefix = \"LS/\"; // implements ls API in particular storage\nconst LsProviderFieldPrefix = \"storage/\"; // provides access to storages list\n\n/** Information about a single data library (LS storage). */\nexport interface StorageInfo {\n /** Machine-stable identifier, e.g. \"library\". Used for filtering and map keys. */\n readonly storageId: string;\n /** Human-readable display name. For V1/legacy equals storageId; for V2 from resource JSON data. */\n readonly storageName: string;\n /** Signed resource ID for this storage resource. */\n readonly resourceId: SignedResourceId;\n /** Full resource type including correct version (\"1\" or \"2\"). */\n readonly resourceType: ResourceType;\n}\n\n/** V2 LsStorage resource JSON data shape (contract with backend). */\ninterface LsStorageV2Data {\n storageName: string;\n storageID: string;\n}\n\n/**\n * Callback type for running transactions. Matches PlClient._withTx signature\n * so the index can run transactions before PlClient is fully initialized.\n */\nexport type TxRunner = <T>(\n name: string,\n writable: boolean,\n clientRoot: OptionalSignedResourceId,\n body: (tx: PlTransaction) => Promise<T>,\n) => Promise<T>;\n\ntype BackendCapability = \"getUserRoot\" | \"listUserResources\" | \"legacy\";\n\n/**\n * Abstracts user resource discovery with backward compatibility.\n *\n * Detects backend capability on the first getUserRoot() call and remembers\n * the result. Three-tier fallback:\n * 1. getUserRoot RPC (newest, supports doNotCreate)\n * 2. listUserResources RPC (streams all resources, picks userRoot)\n * 3. Named resource lookup/creation via transaction (legacy)\n */\nexport class UserResources {\n private backendCapability: BackendCapability | undefined;\n\n constructor(\n private readonly ll: LLPlClient,\n private readonly runTx: TxRunner,\n public readonly authUser: string | null,\n ) {}\n\n /**\n * Returns the user's root resource ID.\n *\n * On first call, detects backend capability by trying methods in order:\n * 1. getUserRoot RPC (newest)\n * 2. listUserResources RPC\n * 3. Named resource lookup/creation via transaction (legacy)\n */\n async getUserRoot(): Promise<SignedResourceId>;\n async getUserRoot(opts: { login?: string }): Promise<SignedResourceId>;\n async getUserRoot(opts: { login?: string; doNotCreate: false }): Promise<SignedResourceId>;\n async getUserRoot(opts: {\n login?: string;\n doNotCreate: true;\n }): Promise<SignedResourceId | undefined>;\n async getUserRoot(\n opts: { login?: string; doNotCreate?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n if (this.backendCapability === undefined) {\n return await this.detectAndGetUserRoot(opts);\n }\n return await this.getUserRootWith(this.backendCapability, opts);\n }\n\n private async detectAndGetUserRoot(\n opts: { login?: string; doNotCreate?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n // 1. Try getUserRoot RPC\n try {\n const root = await this.getUserRootViaRpc(opts);\n this.backendCapability = \"getUserRoot\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 2. Try listUserResources\n try {\n const root = await this.getUserRootViaList(opts);\n this.backendCapability = \"listUserResources\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 3. Legacy fallback\n this.backendCapability = \"legacy\";\n return await this.getUserRootViaLegacy(opts);\n }\n\n private async getUserRootWith(\n capability: BackendCapability,\n opts: { login?: string; doNotCreate?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n switch (capability) {\n case \"getUserRoot\":\n return await this.getUserRootViaRpc(opts);\n case \"listUserResources\":\n return await this.getUserRootViaList(opts);\n case \"legacy\":\n return await this.getUserRootViaLegacy(opts);\n }\n }\n\n /**\n * Returns all data libraries the user has access to.\n * Always fetches fresh from the server (no caching).\n */\n async getDataLibraries(\n opts: { login?: string; doNotCreateUserRoot?: boolean } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n if (this.backendCapability === undefined) {\n // First call — detect backend capability\n try {\n const libs = await this.getDataLibrariesViaList(opts);\n // getUserRoot RPC doesn't return libraries, but listUserResources does;\n // record at least \"listUserResources\" so future getUserRoot calls don't re-detect.\n this.backendCapability = \"listUserResources\";\n return libs;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n this.backendCapability = \"legacy\";\n return await this.getDataLibrariesViaLegacy();\n }\n }\n\n // A server that supports getUserRoot definitely supports listUserResources.\n if (this.backendCapability !== \"legacy\") {\n return await this.getDataLibrariesViaList(opts);\n }\n return await this.getDataLibrariesViaLegacy();\n }\n\n private async getUserRootViaRpc(opts: { login?: string }): Promise<SignedResourceId>;\n private async getUserRootViaRpc(opts: {\n login?: string;\n doNotCreate: false;\n }): Promise<SignedResourceId>;\n private async getUserRootViaRpc(opts: {\n login?: string;\n doNotCreate: true;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaRpc(\n opts: { login?: string; doNotCreate?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const resp = await this.ll.getUserRoot({\n login: opts.login,\n doNotCreate: opts.doNotCreate,\n });\n if (resp.userRoot === undefined) {\n if (opts.doNotCreate) return undefined;\n throw new Error(\"getUserRoot returned no userRoot entry\");\n }\n return createSignedResourceId(\n resp.userRoot.resourceId,\n toResourceSignature(resp.userRoot.resourceSignature),\n );\n }\n\n private async getUserRootViaList(opts: { login?: string }): Promise<SignedResourceId>;\n private async getUserRootViaList(opts: {\n login?: string;\n doNotCreate: false;\n }): Promise<SignedResourceId>;\n private async getUserRootViaList(opts: {\n login?: string;\n doNotCreate: true;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaList(\n opts: { login?: string; doNotCreate?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const responses = await this.ll.listUserResources({ login: opts.login, limit: 1 });\n for (const msg of responses) {\n if (msg.entry.oneofKind === \"userRoot\") {\n return createSignedResourceId(\n msg.entry.userRoot.resourceId,\n toResourceSignature(msg.entry.userRoot.resourceSignature),\n );\n }\n }\n throw new Error(\"listUserResources returned no userRoot entry\");\n }\n\n private async getDataLibrariesViaList(\n opts: { login?: string } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n const responses = await this.ll.listUserResources({ login: opts.login });\n\n // Collect all LS/* shared resources, separating V1 and V2\n const v1Entries: StorageInfo[] = [];\n const v2ResourceIds: { resourceId: SignedResourceId; resourceType: ResourceType }[] = [];\n\n for (const msg of responses) {\n if (msg.entry.oneofKind !== \"sharedResource\") continue;\n const sr = msg.entry.sharedResource;\n\n if (!sr.resourceType) continue;\n const typeName = sr.resourceType.name;\n const typeVersion = sr.resourceType.version;\n if (!typeName.startsWith(LsStorageTypePrefix)) continue;\n\n const rId = createSignedResourceId(sr.resourceId, toResourceSignature(sr.resourceSignature));\n const rType: ResourceType = { name: typeName, version: typeVersion };\n\n if (typeVersion === \"2\") {\n v2ResourceIds.push({ resourceId: rId, resourceType: rType });\n } else {\n // V1 or unknown version: derive storageId from type name\n const storageId = typeName.substring(LsStorageTypePrefix.length);\n v1Entries.push({\n storageId,\n storageName: storageId,\n resourceId: rId,\n resourceType: rType,\n });\n }\n }\n\n // Read V2 resource data in a single transaction\n let v2Entries: StorageInfo[] = [];\n if (v2ResourceIds.length > 0) {\n v2Entries = await this.runTx(\n \"ReadLsStorageV2Data\",\n false,\n NullSignedResourceId,\n async (tx) => {\n const entries: StorageInfo[] = [];\n for (const { resourceId, resourceType } of v2ResourceIds) {\n const rd = await tx.getResourceData(resourceId, false);\n if (rd.data) {\n const v2Data = JSON.parse(Buffer.from(rd.data).toString(\"utf-8\")) as LsStorageV2Data;\n entries.push({\n storageId: v2Data.storageID,\n storageName: v2Data.storageName,\n resourceId,\n resourceType,\n });\n }\n }\n return entries;\n },\n );\n }\n\n const result = new Map<string, StorageInfo>();\n for (const entry of [...v1Entries, ...v2Entries]) {\n result.set(entry.storageId, entry);\n }\n return result;\n }\n\n private async getUserRootViaLegacy(opts: { login?: string }): Promise<SignedResourceId>;\n private async getUserRootViaLegacy(opts: {\n login?: string;\n doNotCreateUserRoot: false;\n }): Promise<SignedResourceId>;\n private async getUserRootViaLegacy(opts: {\n login?: string;\n doNotCreateUserRoot: true;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaLegacy(\n opts: { login?: string; doNotCreateUserRoot?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const login = opts.login ?? this.authUser;\n const mainRootName =\n login === null ? AnonymousClientRoot : createHash(\"sha256\").update(login).digest(\"hex\");\n\n return await this.runTx(\"initialization\", true, NullSignedResourceId, async (tx) => {\n if (await tx.checkResourceNameExists(mainRootName)) {\n return await tx.getResourceByName(mainRootName);\n }\n\n if (opts.doNotCreateUserRoot) {\n return undefined;\n }\n\n const mainRoot = tx.createRoot(ClientRoot);\n tx.setResourceName(mainRootName, mainRoot);\n await tx.commit();\n return await toGlobalResourceId(mainRoot);\n });\n }\n\n private async getDataLibrariesViaLegacy(): Promise<ReadonlyMap<string, StorageInfo>> {\n return await this.runTx(\"GetAvailableStorageIds\", false, NullSignedResourceId, async (tx) => {\n const lsProviderId = await tx.getResourceByName(\"LSProvider\");\n const provider = await tx.getResourceData(lsProviderId, true);\n\n const result = new Map<string, StorageInfo>();\n for (const field of provider.fields) {\n if (field.type !== \"Dynamic\" || !isNotNullSignedResourceId(field.value)) continue;\n if (!field.name.startsWith(LsProviderFieldPrefix)) continue;\n\n const storageId = field.name.substring(LsProviderFieldPrefix.length);\n result.set(storageId, {\n storageId,\n storageName: storageId,\n resourceId: field.value,\n resourceType: { name: `${LsStorageTypePrefix}${storageId}`, version: \"1\" },\n });\n }\n return result;\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { OptionalSignedResourceId, ResourceType, SignedResourceId } from "./types.js";
|
|
2
|
+
import { PlTransaction } from "./transaction.js";
|
|
3
|
+
import { LLPlClient } from "./ll_client.js";
|
|
4
|
+
|
|
5
|
+
//#region src/core/user_resources.d.ts
|
|
6
|
+
/** Information about a single data library (LS storage). */
|
|
7
|
+
interface StorageInfo {
|
|
8
|
+
/** Machine-stable identifier, e.g. "library". Used for filtering and map keys. */
|
|
9
|
+
readonly storageId: string;
|
|
10
|
+
/** Human-readable display name. For V1/legacy equals storageId; for V2 from resource JSON data. */
|
|
11
|
+
readonly storageName: string;
|
|
12
|
+
/** Signed resource ID for this storage resource. */
|
|
13
|
+
readonly resourceId: SignedResourceId;
|
|
14
|
+
/** Full resource type including correct version ("1" or "2"). */
|
|
15
|
+
readonly resourceType: ResourceType;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Callback type for running transactions. Matches PlClient._withTx signature
|
|
19
|
+
* so the index can run transactions before PlClient is fully initialized.
|
|
20
|
+
*/
|
|
21
|
+
type TxRunner = <T>(name: string, writable: boolean, clientRoot: OptionalSignedResourceId, body: (tx: PlTransaction) => Promise<T>) => Promise<T>;
|
|
22
|
+
/**
|
|
23
|
+
* Abstracts user resource discovery with backward compatibility.
|
|
24
|
+
*
|
|
25
|
+
* Detects backend capability on the first getUserRoot() call and remembers
|
|
26
|
+
* the result. Three-tier fallback:
|
|
27
|
+
* 1. getUserRoot RPC (newest, supports doNotCreate)
|
|
28
|
+
* 2. listUserResources RPC (streams all resources, picks userRoot)
|
|
29
|
+
* 3. Named resource lookup/creation via transaction (legacy)
|
|
30
|
+
*/
|
|
31
|
+
declare class UserResources {
|
|
32
|
+
private readonly ll;
|
|
33
|
+
private readonly runTx;
|
|
34
|
+
readonly authUser: string | null;
|
|
35
|
+
private backendCapability;
|
|
36
|
+
constructor(ll: LLPlClient, runTx: TxRunner, authUser: string | null);
|
|
37
|
+
/**
|
|
38
|
+
* Returns the user's root resource ID.
|
|
39
|
+
*
|
|
40
|
+
* On first call, detects backend capability by trying methods in order:
|
|
41
|
+
* 1. getUserRoot RPC (newest)
|
|
42
|
+
* 2. listUserResources RPC
|
|
43
|
+
* 3. Named resource lookup/creation via transaction (legacy)
|
|
44
|
+
*/
|
|
45
|
+
getUserRoot(): Promise<SignedResourceId>;
|
|
46
|
+
getUserRoot(opts: {
|
|
47
|
+
login?: string;
|
|
48
|
+
}): Promise<SignedResourceId>;
|
|
49
|
+
getUserRoot(opts: {
|
|
50
|
+
login?: string;
|
|
51
|
+
doNotCreate: false;
|
|
52
|
+
}): Promise<SignedResourceId>;
|
|
53
|
+
getUserRoot(opts: {
|
|
54
|
+
login?: string;
|
|
55
|
+
doNotCreate: true;
|
|
56
|
+
}): Promise<SignedResourceId | undefined>;
|
|
57
|
+
private detectAndGetUserRoot;
|
|
58
|
+
private getUserRootWith;
|
|
59
|
+
/**
|
|
60
|
+
* Returns all data libraries the user has access to.
|
|
61
|
+
* Always fetches fresh from the server (no caching).
|
|
62
|
+
*/
|
|
63
|
+
getDataLibraries(opts?: {
|
|
64
|
+
login?: string;
|
|
65
|
+
doNotCreateUserRoot?: boolean;
|
|
66
|
+
}): Promise<ReadonlyMap<string, StorageInfo>>;
|
|
67
|
+
private getUserRootViaRpc;
|
|
68
|
+
private getUserRootViaList;
|
|
69
|
+
private getDataLibrariesViaList;
|
|
70
|
+
private getUserRootViaLegacy;
|
|
71
|
+
private getDataLibrariesViaLegacy;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { StorageInfo, TxRunner, UserResources };
|
|
75
|
+
//# sourceMappingURL=user_resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user_resources.d.ts","names":[],"sources":["../../src/core/user_resources.ts"],"mappings":";;;;;;UAmBiB,WAAA;EAAA;EAAA,SAEN,SAAA;;WAEA,WAAA;EAFA;EAAA,SAIA,UAAA,EAAY,gBAAA;EAAZ;EAAA,SAEA,YAAA,EAAc,YAAA;AAAA;;;;AAazB;KAAY,QAAA,OACV,IAAA,UACA,QAAA,WACA,UAAA,EAAY,wBAAA,EACZ,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,MAClC,OAAA,CAAQ,CAAA;;;;;;;;;;cAaA,aAAA;EAAA,iBAIQ,EAAA;EAAA,iBACA,KAAA;EAAA,SACD,QAAA;EAAA,QALV,iBAAA;cAGW,EAAA,EAAI,UAAA,EACJ,KAAA,EAAO,QAAA,EACR,QAAA;EApBX;;;;;;;;EA+BD,WAAA,CAAA,GAAe,OAAA,CAAQ,gBAAA;EACvB,WAAA,CAAY,IAAA;IAAQ,KAAA;EAAA,IAAmB,OAAA,CAAQ,gBAAA;EAC/C,WAAA,CAAY,IAAA;IAAQ,KAAA;IAAgB,WAAA;EAAA,IAAuB,OAAA,CAAQ,gBAAA;EACnE,WAAA,CAAY,IAAA;IAChB,KAAA;IACA,WAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EAAA,QAUE,oBAAA;EAAA,QA0BA,eAAA;EAoBH;;;;EAFL,gBAAA,CACJ,IAAA;IAAQ,KAAA;IAAgB,mBAAA;EAAA,IACvB,OAAA,CAAQ,WAAA,SAAoB,WAAA;EAAA,QAuBjB,iBAAA;EAAA,QA0BA,kBAAA;EAAA,QAwBA,uBAAA;EAAA,QAoEA,oBAAA;EAAA,QAgCA,yBAAA;AAAA"}
|