@evolu/common 6.0.1-preview.2 → 6.0.1-preview.20
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/src/Assert.d.ts +6 -3
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +7 -4
- package/dist/src/Brand.d.ts +75 -0
- package/dist/src/Brand.d.ts.map +1 -0
- package/dist/src/Brand.js +1 -0
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +1 -1
- package/dist/src/CallbackRegistry.d.ts +53 -0
- package/dist/src/CallbackRegistry.d.ts.map +1 -0
- package/dist/src/CallbackRegistry.js +25 -0
- package/dist/src/Console.d.ts +31 -6
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +72 -9
- package/dist/src/Crypto.d.ts +61 -34
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +29 -42
- package/dist/src/Evolu/Db.d.ts +137 -66
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +300 -705
- package/dist/src/Evolu/Diff.d.ts +3 -3
- package/dist/src/Evolu/Diff.d.ts.map +1 -1
- package/dist/src/Evolu/Diff.js +7 -5
- package/dist/src/Evolu/Evolu.d.ts +200 -115
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +287 -157
- package/dist/src/Evolu/Internal.d.ts +0 -2
- package/dist/src/Evolu/Internal.d.ts.map +1 -1
- package/dist/src/Evolu/Internal.js +0 -2
- package/dist/src/Evolu/LocalAuth.d.ts +144 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +171 -0
- package/dist/src/Evolu/Owner.d.ts +152 -127
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +88 -107
- package/dist/src/Evolu/Platform.d.ts +9 -7
- package/dist/src/Evolu/Platform.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.d.ts +170 -186
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +487 -343
- package/dist/src/Evolu/Public.d.ts +6 -8
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Public.js +2 -3
- package/dist/src/Evolu/PublicKysely.js +3 -3
- package/dist/src/Evolu/Query.d.ts +2 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.d.ts +4 -3
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +50 -12
- package/dist/src/Evolu/Schema.d.ts +129 -73
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +169 -89
- package/dist/src/Evolu/Storage.d.ts +159 -14
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +42 -32
- package/dist/src/Evolu/Sync.d.ts +77 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +453 -20
- package/dist/src/Evolu/Timestamp.d.ts +35 -27
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +27 -18
- package/dist/src/ManyToManyMap.d.ts +74 -10
- package/dist/src/ManyToManyMap.d.ts.map +1 -1
- package/dist/src/ManyToManyMap.js +41 -6
- package/dist/src/Number.d.ts +2 -1
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/RefCountedResourceManager.d.ts +119 -0
- package/dist/src/RefCountedResourceManager.d.ts.map +1 -0
- package/dist/src/RefCountedResourceManager.js +197 -0
- package/dist/src/Result.d.ts +147 -51
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +7 -241
- package/dist/src/Sqlite.d.ts +21 -4
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +50 -8
- package/dist/src/Task.d.ts +511 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +410 -0
- package/dist/src/Time.d.ts +59 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +87 -4
- package/dist/src/Type.d.ts +462 -327
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +490 -436
- package/dist/src/Types.d.ts +0 -74
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -13
- package/dist/src/Worker.d.ts +39 -11
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +22 -4
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/package.json +14 -13
- package/src/Assert.ts +8 -7
- package/src/Brand.ts +75 -0
- package/src/Buffer.ts +1 -1
- package/src/CallbackRegistry.ts +84 -0
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +94 -79
- package/src/Evolu/Db.ts +505 -1027
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +682 -329
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +422 -0
- package/src/Evolu/Owner.ts +221 -235
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +681 -614
- package/src/Evolu/Public.ts +7 -14
- package/src/Evolu/PublicKysely.ts +3 -3
- package/src/Evolu/Query.ts +2 -1
- package/src/Evolu/Relay.ts +62 -16
- package/src/Evolu/Schema.ts +391 -191
- package/src/Evolu/Storage.ts +275 -55
- package/src/Evolu/Sync.ts +758 -37
- package/src/Evolu/Timestamp.ts +38 -35
- package/src/ManyToManyMap.ts +127 -24
- package/src/Number.ts +2 -6
- package/src/Random.ts +3 -2
- package/src/RefCountedResourceManager.ts +368 -0
- package/src/Result.ts +152 -53
- package/src/Sqlite.ts +59 -23
- package/src/Task.ts +779 -0
- package/src/Time.ts +168 -4
- package/src/Type.ts +696 -660
- package/src/Types.ts +0 -76
- package/src/WebSocket.ts +23 -17
- package/src/Worker.ts +72 -23
- package/src/index.ts +3 -3
- package/dist/src/Callbacks.d.ts +0 -20
- package/dist/src/Callbacks.d.ts.map +0 -1
- package/dist/src/Callbacks.js +0 -18
- package/dist/src/Evolu/Config.d.ts +0 -69
- package/dist/src/Evolu/Config.d.ts.map +0 -1
- package/dist/src/Evolu/Config.js +0 -9
- package/dist/src/Evolu/Kysely.d.ts +0 -6
- package/dist/src/Evolu/Kysely.d.ts.map +0 -1
- package/dist/src/Evolu/Kysely.js +0 -21
- package/dist/src/NanoId.d.ts +0 -27
- package/dist/src/NanoId.d.ts.map +0 -1
- package/dist/src/NanoId.js +0 -6
- package/dist/src/Promise.d.ts +0 -180
- package/dist/src/Promise.d.ts.map +0 -1
- package/dist/src/Promise.js +0 -176
- package/src/Callbacks.ts +0 -43
- package/src/Evolu/Config.ts +0 -83
- package/src/Evolu/Kysely.ts +0 -38
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { RandomBytesDep } from "../Crypto.js";
|
|
2
|
+
import { Mnemonic } from "../Type.js";
|
|
3
|
+
import { AppOwner, OwnerId } from "./Owner.js";
|
|
4
|
+
/** @experimental */
|
|
5
|
+
export interface LocalAuth {
|
|
6
|
+
/** Logs in with the given owner ID, or loads the target owner if not provided. */
|
|
7
|
+
login: (ownerId?: OwnerId, options?: LocalAuthOptions & {
|
|
8
|
+
reloadNeeded?: boolean;
|
|
9
|
+
}) => Promise<AuthResult | null>;
|
|
10
|
+
/** Registers a new owner with the given username. */
|
|
11
|
+
register: (username: string, options?: LocalAuthOptions & {
|
|
12
|
+
mnemonic?: Mnemonic | null;
|
|
13
|
+
}) => Promise<AuthResult | null>;
|
|
14
|
+
/** Unregisters an owner with the given owner ID. */
|
|
15
|
+
unregister: (ownerId: OwnerId, options?: LocalAuthOptions) => Promise<void>;
|
|
16
|
+
/** Lists all registered owner ids with associated usernames. */
|
|
17
|
+
getProfiles: (options?: LocalAuthOptionsValues) => Promise<Array<{
|
|
18
|
+
ownerId: OwnerId;
|
|
19
|
+
username: string;
|
|
20
|
+
}>>;
|
|
21
|
+
/** Clears all owners and metadata from the local auth. */
|
|
22
|
+
clearAll: (options?: LocalAuthOptions) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export interface LocalAuthDep {
|
|
25
|
+
readonly localAuth: LocalAuth;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* - **⚠️
|
|
29
|
+
*
|
|
30
|
+
* Secure storage interface that must be implemented by each platform.
|
|
31
|
+
*/
|
|
32
|
+
export interface SecureStorage {
|
|
33
|
+
setItem: (key: string, value: string, options?: LocalAuthOptions) => Promise<MutationResult>;
|
|
34
|
+
getItem: (key: string, options?: LocalAuthOptionsValues) => Promise<SensitiveInfoItem | null>;
|
|
35
|
+
deleteItem: (key: string, options?: LocalAuthOptions) => Promise<boolean>;
|
|
36
|
+
getAllItems: (options?: LocalAuthOptionsValues) => Promise<Array<SensitiveInfoItem>>;
|
|
37
|
+
clearService: (options?: LocalAuthOptions) => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export interface SecureStorageDep {
|
|
40
|
+
readonly secureStorage: SecureStorage;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a local auth using the given secure storage implementation. This
|
|
44
|
+
* factory function allows each platform to provide its own storage layer while
|
|
45
|
+
* sharing the common auth logic.
|
|
46
|
+
*/
|
|
47
|
+
export declare const createLocalAuth: (deps: SecureStorageDep & RandomBytesDep) => LocalAuth;
|
|
48
|
+
export declare const AUTH_NAMESPACE = "evolu";
|
|
49
|
+
export declare const AUTH_METAKEY_LAST_OWNER = "_last_owner";
|
|
50
|
+
export declare const AUTH_METAKEY_OWNER_NAMES = "_owner_names";
|
|
51
|
+
export declare const AUTH_DEFAULT_OPTIONS: LocalAuthOptions;
|
|
52
|
+
export interface AuthResult {
|
|
53
|
+
/** The owner created during registration. */
|
|
54
|
+
readonly owner: AppOwner | undefined;
|
|
55
|
+
/** The name provided by the user during registration. */
|
|
56
|
+
readonly username: string;
|
|
57
|
+
}
|
|
58
|
+
export interface LocalAuthOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Native: Namespaces the stored entry. Defaults to the bundle identifier
|
|
61
|
+
* (when available) or `default`.
|
|
62
|
+
*/
|
|
63
|
+
readonly service?: string;
|
|
64
|
+
/** IOS: Enable keychain item synchronization via iCloud. */
|
|
65
|
+
readonly iosSynchronizable?: boolean;
|
|
66
|
+
/** IOS: Custom keychain access group. */
|
|
67
|
+
readonly keychainGroup?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Native: Desired access-control policy. The native implementation will
|
|
70
|
+
* automatically fall back to the strongest supported policy for the current
|
|
71
|
+
* device (Secure Enclave ➝ Biometry ➝ Device Credential ➝ None).
|
|
72
|
+
*/
|
|
73
|
+
readonly accessControl?: AccessControl;
|
|
74
|
+
/**
|
|
75
|
+
* Android: Fine tune whether the hardware-authenticated key should require
|
|
76
|
+
* biometrics only.
|
|
77
|
+
*/
|
|
78
|
+
readonly androidBiometricsStrongOnly?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Native: Optional prompt configuration that will be shown when protected
|
|
81
|
+
* keys require user presence.
|
|
82
|
+
*/
|
|
83
|
+
readonly authenticationPrompt?: AuthenticationPrompt;
|
|
84
|
+
/** Web: The relying party ID for WebAuthn. Defaults to the current hostname. */
|
|
85
|
+
readonly relyingPartyID?: string;
|
|
86
|
+
/** Web: The relying party name for WebAuthn. Defaults to 'Evolu'. */
|
|
87
|
+
readonly relyingPartyName?: string;
|
|
88
|
+
/** Web: The username for WebAuthn. Defaults to 'Evolu User'. */
|
|
89
|
+
readonly webAuthnUsername?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Web: The user verification requirement for WebAuthn. Defaults to
|
|
92
|
+
* 'required'.
|
|
93
|
+
*/
|
|
94
|
+
readonly webAuthnUserVerification?: UserVerificationRequirement;
|
|
95
|
+
/** Web: The authenticator attachment for WebAuthn. Defaults to 'platform'. */
|
|
96
|
+
readonly webAuthnAuthenticatorAttachment?: AuthenticatorAttachment;
|
|
97
|
+
}
|
|
98
|
+
export interface LocalAuthOptionsValues extends LocalAuthOptions {
|
|
99
|
+
/** When true, the stored value is returned for each item. Defaults to false. */
|
|
100
|
+
readonly includeValues?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Configuration for the biometric/device credential prompt shown when a
|
|
104
|
+
* protected item is accessed.
|
|
105
|
+
*/
|
|
106
|
+
export interface AuthenticationPrompt {
|
|
107
|
+
readonly title: string;
|
|
108
|
+
readonly subtitle?: string;
|
|
109
|
+
readonly description?: string;
|
|
110
|
+
readonly cancel?: string;
|
|
111
|
+
}
|
|
112
|
+
export interface SensitiveInfoGetRequest extends LocalAuthOptions {
|
|
113
|
+
readonly key: string;
|
|
114
|
+
/** Include the encrypted value when available. Defaults to true. */
|
|
115
|
+
readonly includeValue?: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface StorageMetadata {
|
|
118
|
+
readonly securityLevel: SecurityLevel;
|
|
119
|
+
readonly backend: StorageBackend;
|
|
120
|
+
readonly accessControl: AccessControl;
|
|
121
|
+
readonly timestamp: number;
|
|
122
|
+
}
|
|
123
|
+
export interface SensitiveInfoItem {
|
|
124
|
+
readonly key: string;
|
|
125
|
+
readonly service: string;
|
|
126
|
+
readonly value?: string;
|
|
127
|
+
readonly metadata: StorageMetadata;
|
|
128
|
+
}
|
|
129
|
+
export interface MutationResult {
|
|
130
|
+
readonly metadata: StorageMetadata;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Enumerates the highest security tier that was effectively applied while
|
|
134
|
+
* storing a value.
|
|
135
|
+
*/
|
|
136
|
+
export type SecurityLevel = "secureEnclave" | "strongBox" | "biometry" | "deviceCredential" | "software";
|
|
137
|
+
/** Enumerates the native storage backend used to persist sensitive data. */
|
|
138
|
+
export type StorageBackend = "keychain" | "androidKeystore" | "encryptedSharedPreferences";
|
|
139
|
+
/**
|
|
140
|
+
* Enumerates the access-control policy enforced by the underlying secure
|
|
141
|
+
* storage.
|
|
142
|
+
*/
|
|
143
|
+
export type AccessControl = "secureEnclaveBiometry" | "biometryCurrentSet" | "biometryAny" | "devicePasscode" | "none";
|
|
144
|
+
//# sourceMappingURL=LocalAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalAuth.d.ts","sourceRoot":"","sources":["../../../src/Evolu/LocalAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createAppOwner, createOwnerSecret, mnemonicToOwnerSecret, OwnerEncryptionKey, OwnerWriteKey, } from "./Owner.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a local auth using the given secure storage implementation. This
|
|
4
|
+
* factory function allows each platform to provide its own storage layer while
|
|
5
|
+
* sharing the common auth logic.
|
|
6
|
+
*/
|
|
7
|
+
export const createLocalAuth = (deps) => {
|
|
8
|
+
const setLastOwnerId = async (id, options) => {
|
|
9
|
+
await deps.secureStorage.setItem(AUTH_METAKEY_LAST_OWNER, id, {
|
|
10
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
11
|
+
...options,
|
|
12
|
+
accessControl: "none",
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
const getLastOwnerId = async (options) => {
|
|
16
|
+
const item = await deps.secureStorage.getItem(AUTH_METAKEY_LAST_OWNER, {
|
|
17
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
18
|
+
...options,
|
|
19
|
+
accessControl: "none",
|
|
20
|
+
});
|
|
21
|
+
return item?.value;
|
|
22
|
+
};
|
|
23
|
+
const getOwnerNames = async (options) => {
|
|
24
|
+
const item = await deps.secureStorage.getItem(AUTH_METAKEY_OWNER_NAMES, {
|
|
25
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
26
|
+
...options,
|
|
27
|
+
accessControl: "none",
|
|
28
|
+
});
|
|
29
|
+
let names = {};
|
|
30
|
+
if (item?.value) {
|
|
31
|
+
names = JSON.parse(item.value);
|
|
32
|
+
}
|
|
33
|
+
return names;
|
|
34
|
+
};
|
|
35
|
+
const setOwnerName = async (id, username, options) => {
|
|
36
|
+
const names = await getOwnerNames(options);
|
|
37
|
+
names[id] = username;
|
|
38
|
+
await deps.secureStorage.setItem(AUTH_METAKEY_OWNER_NAMES, JSON.stringify(names), {
|
|
39
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
40
|
+
...options,
|
|
41
|
+
accessControl: "none",
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const deleteOwnerName = async (id, options) => {
|
|
45
|
+
const { [id]: _, ...names } = await getOwnerNames(options);
|
|
46
|
+
await deps.secureStorage.setItem(AUTH_METAKEY_OWNER_NAMES, JSON.stringify(names), {
|
|
47
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
48
|
+
...options,
|
|
49
|
+
accessControl: "none",
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const getOwnerIds = async (options) => {
|
|
53
|
+
const items = await deps.secureStorage.getAllItems({
|
|
54
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
55
|
+
...options,
|
|
56
|
+
includeValues: false,
|
|
57
|
+
});
|
|
58
|
+
return items
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.filter((i) => i.key !== AUTH_METAKEY_LAST_OWNER &&
|
|
61
|
+
i.key !== AUTH_METAKEY_OWNER_NAMES)
|
|
62
|
+
.map((i) => i.key);
|
|
63
|
+
};
|
|
64
|
+
const clearAuthStore = (options) => deps.secureStorage.clearService({
|
|
65
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
66
|
+
...options,
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
login: async (ownerId, options) => {
|
|
70
|
+
// Use either specified owner or the last owner used during registration/login.
|
|
71
|
+
const targetOwnerId = ownerId ?? (await getLastOwnerId(options));
|
|
72
|
+
if (!targetOwnerId)
|
|
73
|
+
return null;
|
|
74
|
+
// Lookup the associated username
|
|
75
|
+
const names = await getOwnerNames(options);
|
|
76
|
+
const username = names[targetOwnerId] ?? "";
|
|
77
|
+
// If a reload is needed, avoid authentication, it needs to be handled on next page load.
|
|
78
|
+
// We set the last owner so we know what the target is.
|
|
79
|
+
// It is the applications's responsibility to reload and trigger login.
|
|
80
|
+
if (options?.reloadNeeded) {
|
|
81
|
+
await setLastOwnerId(targetOwnerId, options);
|
|
82
|
+
return { owner: undefined, username };
|
|
83
|
+
}
|
|
84
|
+
// Retrieve and decrypt the owner (this will trigger device authentication)
|
|
85
|
+
const account = await deps.secureStorage.getItem(targetOwnerId, {
|
|
86
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
87
|
+
...options,
|
|
88
|
+
});
|
|
89
|
+
if (!account?.value)
|
|
90
|
+
return null;
|
|
91
|
+
// Unserialize the values (TODO: save these as base64 instead of json serializing)
|
|
92
|
+
const result = JSON.parse(account.value);
|
|
93
|
+
const writeKey = OwnerWriteKey.orThrow(new Uint8Array(Object.values(result.owner.writeKey)));
|
|
94
|
+
const encryptionKey = OwnerEncryptionKey.orThrow(new Uint8Array(Object.values(result.owner.encryptionKey)));
|
|
95
|
+
const owner = { ...result.owner, writeKey, encryptionKey };
|
|
96
|
+
// Update the last owner for future login attempts
|
|
97
|
+
await setLastOwnerId(targetOwnerId, options);
|
|
98
|
+
// Return the owner and associated username
|
|
99
|
+
return { owner, username };
|
|
100
|
+
},
|
|
101
|
+
register: async (username, options) => {
|
|
102
|
+
// Create an owner with a new secret or use specified mnemonic
|
|
103
|
+
const owner = createAppOwner(options?.mnemonic
|
|
104
|
+
? mnemonicToOwnerSecret(options.mnemonic)
|
|
105
|
+
: createOwnerSecret(deps));
|
|
106
|
+
// Store owner, associated username, and update last owner
|
|
107
|
+
await Promise.all([
|
|
108
|
+
// setOwnerItem
|
|
109
|
+
deps.secureStorage.setItem(owner.id, JSON.stringify({ owner }), {
|
|
110
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
111
|
+
webAuthnUsername: username,
|
|
112
|
+
...options,
|
|
113
|
+
}),
|
|
114
|
+
setOwnerName(owner.id, username, options),
|
|
115
|
+
setLastOwnerId(owner.id, options),
|
|
116
|
+
]);
|
|
117
|
+
// Return the owner and associated username
|
|
118
|
+
return { owner, username };
|
|
119
|
+
},
|
|
120
|
+
unregister: async (ownerId, options) => {
|
|
121
|
+
// Delete the owner and associated username
|
|
122
|
+
await Promise.all([
|
|
123
|
+
// deleteOwnerItem
|
|
124
|
+
deps.secureStorage.deleteItem(ownerId, {
|
|
125
|
+
...AUTH_DEFAULT_OPTIONS,
|
|
126
|
+
...options,
|
|
127
|
+
}),
|
|
128
|
+
deleteOwnerName(ownerId, options),
|
|
129
|
+
]);
|
|
130
|
+
// If the owner was the last owner then set to
|
|
131
|
+
// the next owner based on metadata timestamp
|
|
132
|
+
const lastOwnerId = await getLastOwnerId(options);
|
|
133
|
+
if (lastOwnerId === ownerId) {
|
|
134
|
+
const ids = await getOwnerIds(options);
|
|
135
|
+
if (ids.length > 0) {
|
|
136
|
+
await setLastOwnerId(ids[0], options);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
getProfiles: async (options) => {
|
|
141
|
+
// Get all owner ids and associated usernames
|
|
142
|
+
const [ids, names] = await Promise.all([
|
|
143
|
+
getOwnerIds(options),
|
|
144
|
+
getOwnerNames(options),
|
|
145
|
+
]);
|
|
146
|
+
// Return the list of profiles (usually used for login UX)
|
|
147
|
+
return ids.map((ownerId) => ({
|
|
148
|
+
ownerId,
|
|
149
|
+
username: names[ownerId] ?? "",
|
|
150
|
+
}));
|
|
151
|
+
},
|
|
152
|
+
clearAll: async (options) => {
|
|
153
|
+
// Delete all owners and associated metadata (scoped to the service)
|
|
154
|
+
await clearAuthStore(options);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
// TOHO: With `const`, we don't need UPPER_CASE
|
|
159
|
+
export const AUTH_NAMESPACE = "evolu";
|
|
160
|
+
export const AUTH_METAKEY_LAST_OWNER = "_last_owner";
|
|
161
|
+
export const AUTH_METAKEY_OWNER_NAMES = "_owner_names";
|
|
162
|
+
export const AUTH_DEFAULT_OPTIONS = {
|
|
163
|
+
service: AUTH_NAMESPACE,
|
|
164
|
+
keychainGroup: AUTH_NAMESPACE,
|
|
165
|
+
androidBiometricsStrongOnly: true,
|
|
166
|
+
iosSynchronizable: true,
|
|
167
|
+
webAuthnUsername: "Evolu User",
|
|
168
|
+
authenticationPrompt: {
|
|
169
|
+
title: "Authenticate to unlock your session",
|
|
170
|
+
},
|
|
171
|
+
};
|
|
@@ -1,160 +1,185 @@
|
|
|
1
|
+
import { NonEmptyReadonlyArray } from "../Array.js";
|
|
2
|
+
import { EncryptionKey, RandomBytesDep } from "../Crypto.js";
|
|
3
|
+
import { Mnemonic, NonNegativeInt } from "../Type.js";
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
5
|
+
* 32 bytes of cryptographic entropy used to derive {@link Owner} keys.
|
|
3
6
|
*
|
|
4
|
-
* @
|
|
7
|
+
* Can be created using {@link createOwnerSecret} or converted from a
|
|
8
|
+
* {@link Mnemonic} using {@link mnemonicToOwnerSecret}.
|
|
5
9
|
*/
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
export declare const OwnerSecret: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", Uint8Array<ArrayBufferLike> & import("../Brand.js").Brand<"Entropy">, Uint8Array<ArrayBufferLike>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>, Uint8Array<ArrayBufferLike>, never>, "Length32", import("../Type.js").LengthError<32>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>>, "OwnerSecret", import("../Type.js").BrandWithoutRefineError<"OwnerSecret", import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError> | import("../Type.js").LengthError<32>>, never>;
|
|
11
|
+
export type OwnerSecret = typeof OwnerSecret.Type;
|
|
12
|
+
/** Creates a {@link OwnerSecret}. */
|
|
13
|
+
export declare const createOwnerSecret: (deps: RandomBytesDep) => OwnerSecret;
|
|
14
|
+
/** Converts an {@link OwnerSecret} to a {@link Mnemonic}. */
|
|
15
|
+
export declare const ownerSecretToMnemonic: (secret: OwnerSecret) => Mnemonic;
|
|
16
|
+
/** Converts a {@link Mnemonic} to an {@link OwnerSecret}. */
|
|
17
|
+
export declare const mnemonicToOwnerSecret: (mnemonic: Mnemonic) => OwnerSecret;
|
|
11
18
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
19
|
+
* The Owner represents ownership of data in Evolu. Every database change is
|
|
20
|
+
* assigned to an owner, enabling sync functionality and access control.
|
|
21
|
+
*
|
|
22
|
+
* Owners enable **partial sync** - applications can choose which owners to
|
|
23
|
+
* sync, allowing selective data synchronization based on specific needs.
|
|
24
|
+
*
|
|
25
|
+
* Owners also provide **real data deletion** - while individual changes in
|
|
26
|
+
* local-first/distributed systems can only be marked as deleted, entire owners
|
|
27
|
+
* can be completely deleted from both relays and devices (except for
|
|
28
|
+
* {@link AppOwner}, which must be preserved for sync coordination).
|
|
29
|
+
*
|
|
30
|
+
* Evolu provides different owner types depending on their use case:
|
|
31
|
+
*
|
|
32
|
+
* - **Coordination**: {@link AppOwner} for sync coordination and long-term
|
|
33
|
+
* persistence
|
|
34
|
+
* - **Data partitioning**: {@link ShardOwner} for partitioning application data
|
|
35
|
+
* - **Collaboration**: {@link SharedOwner} for collaborative write access
|
|
36
|
+
* - **Data sharing**: {@link SharedReadonlyOwner} for read-only access to shared
|
|
37
|
+
* data
|
|
38
|
+
*
|
|
39
|
+
* Owners are cryptographically derived from an {@link OwnerSecret} using
|
|
40
|
+
* SLIP-21, ensuring secure and deterministic key generation:
|
|
41
|
+
*
|
|
42
|
+
* - {@link OwnerId}: Globally unique public identifier
|
|
43
|
+
* - {@link EncryptionKey}: Symmetric encryption key for data protection
|
|
44
|
+
* - {@link OwnerWriteKey}: Authentication token for write operations (rotatable)
|
|
45
|
+
*
|
|
46
|
+
* @see {@link createOwner}
|
|
29
47
|
*/
|
|
30
48
|
export interface Owner {
|
|
31
|
-
readonly mnemonic: Mnemonic;
|
|
32
|
-
readonly createdAt: DateIsoString;
|
|
33
49
|
readonly id: OwnerId;
|
|
34
|
-
readonly encryptionKey:
|
|
35
|
-
readonly writeKey:
|
|
36
|
-
}
|
|
37
|
-
export interface OwnerWithWriteAccess {
|
|
38
|
-
readonly id: OwnerId;
|
|
39
|
-
readonly encryptionKey: EncryptionKey;
|
|
40
|
-
readonly writeKey: WriteKey;
|
|
50
|
+
readonly encryptionKey: OwnerEncryptionKey;
|
|
51
|
+
readonly writeKey: OwnerWriteKey;
|
|
41
52
|
}
|
|
42
53
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* This branded {@link Id} type, generated by {@link createSlip21Id}, is a
|
|
46
|
-
* 21-character {@link Base64Url} string (126 bits of entropy), providing a
|
|
47
|
-
* compact, shareable, and secure identifier for UI use, tied to the owner's
|
|
48
|
-
* mnemonic and derivation path.
|
|
54
|
+
* OwnerId is a branded {@link Id} that uniquely identifies an {@link Owner}.
|
|
55
|
+
* Branded from {@link Id} to leverage existing helpers like {@link idToIdBytes}.
|
|
49
56
|
*/
|
|
50
|
-
export declare const OwnerId: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").
|
|
57
|
+
export declare const OwnerId: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").IdError, import("../Type.js").StringError>, "OwnerId", import("../Type.js").BrandWithoutRefineError<"OwnerId", import("../Type.js").StringError | import("../Type.js").IdError>, never>;
|
|
51
58
|
export type OwnerId = typeof OwnerId.Type;
|
|
52
|
-
|
|
59
|
+
/** Bytes representation of {@link OwnerId}. */
|
|
60
|
+
export declare const OwnerIdBytes: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>, "Length16", import("../Type.js").LengthError<16>, import("../Type.js").Uint8ArrayError>, "IdBytes", import("../Type.js").BrandWithoutRefineError<"IdBytes", import("../Type.js").LengthError<16> | import("../Type.js").Uint8ArrayError>, never>, "OwnerIdBytes", import("../Type.js").BrandWithoutRefineError<"OwnerIdBytes", import("../Type.js").BrandWithoutRefineError<"IdBytes", import("../Type.js").LengthError<16> | import("../Type.js").Uint8ArrayError>>, never>;
|
|
61
|
+
export type OwnerIdBytes = typeof OwnerIdBytes.Type;
|
|
62
|
+
export declare const ownerIdToOwnerIdBytes: (ownerId: OwnerId) => OwnerIdBytes;
|
|
63
|
+
export declare const ownerIdBytesToOwnerId: (ownerIdBytes: OwnerIdBytes) => OwnerId;
|
|
64
|
+
export declare const ownerWriteKeyLength: NonNegativeInt;
|
|
65
|
+
export declare const OwnerEncryptionKey: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", Uint8Array<ArrayBufferLike> & import("../Brand.js").Brand<"Entropy">, Uint8Array<ArrayBufferLike>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>, Uint8Array<ArrayBufferLike>, never>, "Length32", import("../Type.js").LengthError<32>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>>, "EncryptionKey", import("../Type.js").BrandWithoutRefineError<"EncryptionKey", import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError> | import("../Type.js").LengthError<32>>, never>, "OwnerEncryptionKey", import("../Type.js").BrandWithoutRefineError<"OwnerEncryptionKey", import("../Type.js").BrandWithoutRefineError<"EncryptionKey", import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError> | import("../Type.js").LengthError<32>>>, never>;
|
|
66
|
+
export type OwnerEncryptionKey = typeof OwnerEncryptionKey.Type;
|
|
53
67
|
/**
|
|
54
|
-
* A secure token
|
|
55
|
-
*
|
|
68
|
+
* A secure token for write operations. It's derived from {@link OwnerSecret} by
|
|
69
|
+
* default and can be rotated via {@link createOwnerWriteKey}.
|
|
56
70
|
*/
|
|
57
|
-
export declare const
|
|
58
|
-
export type
|
|
71
|
+
export declare const OwnerWriteKey: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", Uint8Array<ArrayBufferLike> & import("../Brand.js").Brand<"Entropy">, Uint8Array<ArrayBufferLike>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>, Uint8Array<ArrayBufferLike>, never>, "Length16", import("../Type.js").LengthError<16>, import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>>, "OwnerWriteKey", import("../Type.js").BrandWithoutRefineError<"OwnerWriteKey", import("../Type.js").LengthError<16> | import("../Type.js").BrandWithoutRefineError<"Entropy", import("../Type.js").Uint8ArrayError>>, never>;
|
|
72
|
+
export type OwnerWriteKey = typeof OwnerWriteKey.Type;
|
|
73
|
+
/** Creates a randomly generated {@link OwnerWriteKey}. */
|
|
74
|
+
export declare const createOwnerWriteKey: (deps: RandomBytesDep) => OwnerWriteKey;
|
|
59
75
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
76
|
+
* Creates an {@link Owner} from a {@link OwnerSecret} using SLIP-21 key
|
|
77
|
+
* derivation.
|
|
78
|
+
*
|
|
79
|
+
* This is an internal helper function, use:
|
|
80
|
+
*
|
|
81
|
+
* - {@link createAppOwner}
|
|
82
|
+
* - {@link createShardOwner}
|
|
83
|
+
* - {@link createSharedOwner}
|
|
84
|
+
* - {@link createSharedReadonlyOwner}
|
|
85
|
+
*/
|
|
86
|
+
export declare const createOwner: (secret: OwnerSecret) => Owner;
|
|
87
|
+
/**
|
|
88
|
+
* The AppOwner represents the application owner. It's created using a
|
|
89
|
+
* cryptographically secure random generator or derived from an external source,
|
|
90
|
+
* e.g., mnemonic stored securely in a hardware device.
|
|
91
|
+
*
|
|
92
|
+
* While it's possible to store all application data in AppOwner, the better
|
|
93
|
+
* approach is to use it only for sync coordination. Storing all app data in
|
|
94
|
+
* AppOwner means that data will be stored/synced forever. And that's a problem
|
|
95
|
+
* if we want to provide real data deletion or in-app data migration without
|
|
96
|
+
* data duplication. In local-first apps/distributed systems, we can't delete
|
|
97
|
+
* individual changes, we only mark them as deleted, otherwise sync could not
|
|
98
|
+
* work.
|
|
99
|
+
*
|
|
100
|
+
* If we really want to delete data or at least avoid syncing it, we must store
|
|
101
|
+
* it using a different owner than AppOwner, e.g. {@link ShardOwner} or
|
|
102
|
+
* {@link SharedOwner}, and delete that owner. The AppOwner itself must be
|
|
103
|
+
* preserved because it coordinates deletion information across devices. Other
|
|
104
|
+
* devices need to sync the information that an owner was deleted so they can
|
|
105
|
+
* delete their local data as well.
|
|
65
106
|
*/
|
|
66
107
|
export interface AppOwner extends Owner {
|
|
67
108
|
readonly type: "AppOwner";
|
|
109
|
+
/**
|
|
110
|
+
* The mnemonic that was used to derive the AppOwner keys. Optional when the
|
|
111
|
+
* AppOwner is created from external keys to avoid sharing the mnemonic with
|
|
112
|
+
* the Evolu app.
|
|
113
|
+
*/
|
|
114
|
+
readonly mnemonic?: Mnemonic | null;
|
|
115
|
+
}
|
|
116
|
+
/** Creates an {@link AppOwner} from an {@link OwnerSecret}. */
|
|
117
|
+
export declare const createAppOwner: (secret: OwnerSecret) => AppOwner;
|
|
118
|
+
export type TransportConfig = WebSocketTransportConfig;
|
|
119
|
+
export interface WebSocketTransportConfig {
|
|
120
|
+
readonly type: "WebSocket";
|
|
121
|
+
readonly url: string;
|
|
68
122
|
}
|
|
69
123
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
124
|
+
* An {@link Owner} for sharding data.
|
|
125
|
+
*
|
|
126
|
+
* ShardOwners are the recommended storage location for most application data
|
|
127
|
+
* because they can be completely deleted (both on relays and devices) and
|
|
128
|
+
* conditionally synced.
|
|
129
|
+
*
|
|
130
|
+
* Can be created from {@link OwnerSecret} via {@link createShardOwner} or
|
|
131
|
+
* deterministically derived from {@link AppOwner} using
|
|
132
|
+
* {@link deriveShardOwner}.
|
|
78
133
|
*/
|
|
79
|
-
export interface ShardOwner {
|
|
134
|
+
export interface ShardOwner extends Owner {
|
|
80
135
|
readonly type: "ShardOwner";
|
|
81
|
-
readonly
|
|
82
|
-
readonly writeKey: WriteKey;
|
|
136
|
+
readonly transports?: ReadonlyArray<TransportConfig>;
|
|
83
137
|
}
|
|
138
|
+
/** Creates a {@link ShardOwner} from an {@link OwnerSecret}. */
|
|
139
|
+
export declare const createShardOwner: (secret: OwnerSecret, transports?: ReadonlyArray<TransportConfig>) => ShardOwner;
|
|
84
140
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
141
|
+
* Derives a {@link ShardOwner} from an {@link AppOwner} using the specified path.
|
|
142
|
+
*
|
|
143
|
+
* **Advantages of derived owners:**
|
|
144
|
+
*
|
|
145
|
+
* - **Deterministic**: Same path always produces the same ShardOwner across all
|
|
146
|
+
* devices
|
|
147
|
+
* - **Immediate availability**: Can be hardcoded and used before sync occurs
|
|
148
|
+
* - **Consistent setup**: All devices start with identical data structure
|
|
149
|
+
* - **Lifecycle management**: Can implement epoch patterns for clean data
|
|
150
|
+
* deletion and recreation
|
|
151
|
+
*
|
|
152
|
+
* **Common patterns:**
|
|
153
|
+
*
|
|
154
|
+
* - Use paths like `["shard", 1]` for versioned data lifecycle
|
|
155
|
+
* - Use paths like `["project", "MyApp", 1]` for named partitions with versions
|
|
156
|
+
* - Each device can derive the same owners and set up initial structure
|
|
94
157
|
*/
|
|
95
|
-
export
|
|
158
|
+
export declare const deriveShardOwner: (owner: AppOwner, path: NonEmptyReadonlyArray<string | number>, transports?: ReadonlyArray<TransportConfig>) => ShardOwner;
|
|
159
|
+
/** An {@link Owner} for collaborative data with write access. */
|
|
160
|
+
export interface SharedOwner extends Owner {
|
|
96
161
|
readonly type: "SharedOwner";
|
|
97
|
-
readonly
|
|
98
|
-
readonly writeKey: WriteKey;
|
|
162
|
+
readonly transports?: ReadonlyArray<TransportConfig>;
|
|
99
163
|
}
|
|
100
164
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
165
|
+
* Creates a {@link SharedOwner} from an {@link OwnerSecret} for collaborative
|
|
166
|
+
* write access.
|
|
167
|
+
*
|
|
168
|
+
* Use {@link createSharedReadonlyOwner} to create a read-only version for
|
|
169
|
+
* sharing.
|
|
170
|
+
*/
|
|
171
|
+
export declare const createSharedOwner: (secret: OwnerSecret, transports?: ReadonlyArray<TransportConfig>) => SharedOwner;
|
|
172
|
+
/**
|
|
173
|
+
* Read-only version of a {@link SharedOwner} for data sharing. Contains only the
|
|
174
|
+
* {@link OwnerId} and {@link EncryptionKey} needed for others to read the shared
|
|
175
|
+
* data without write access.
|
|
106
176
|
*/
|
|
107
177
|
export interface SharedReadonlyOwner {
|
|
108
178
|
readonly type: "SharedReadonlyOwner";
|
|
109
|
-
readonly
|
|
179
|
+
readonly id: OwnerId;
|
|
180
|
+
readonly encryptionKey: EncryptionKey;
|
|
181
|
+
readonly transports?: ReadonlyArray<TransportConfig>;
|
|
110
182
|
}
|
|
111
|
-
/**
|
|
112
|
-
* Creates an {@link AppOwner}, optionally from an existing mnemonic to restore
|
|
113
|
-
* it on another device; otherwise, generates a new mnemonic.
|
|
114
|
-
*/
|
|
115
|
-
export declare const createAppOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => (mnemonic?: string & import("../Types.js").Brand<"Trimmed"> & import("../Types.js").Brand<"MinLength1"> & import("../Types.js").Brand<"Mnemonic">) => AppOwner;
|
|
116
|
-
/**
|
|
117
|
-
* Creates a {@link ShardOwner} for sharding app data with a freshly generated
|
|
118
|
-
* mnemonic. Unlike {@link createAppOwner}, it doesn’t accept an existing
|
|
119
|
-
* mnemonic because ShardOwner mnemonics are always generated and restored
|
|
120
|
-
* automatically via database sync.
|
|
121
|
-
*/
|
|
122
|
-
export declare const createShardOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => ShardOwner;
|
|
123
|
-
/**
|
|
124
|
-
* Creates a fresh {@link SharedOwner} for sharing data with write access. Takes
|
|
125
|
-
* no arguments as both `mnemonic` and rotatable `writeKey` are newly generated;
|
|
126
|
-
* when shared, recipients use the provided `mnemonic` and `writeKey` directly
|
|
127
|
-
* as a {@link SharedOwner} without needing to recreate it.
|
|
128
|
-
*/
|
|
129
|
-
export declare const createSharedOwner: (deps: CreateRandomBytesDep & CreateMnemonicDep) => SharedOwner;
|
|
130
|
-
/**
|
|
131
|
-
* Creates a {@link SharedReadonlyOwner} from a {@link SharedOwner} for read-only
|
|
132
|
-
* data sharing. Extracts the `mnemonic` from the provided {@link SharedOwner},
|
|
133
|
-
* omitting its `writeKey` to ensure read-only access.
|
|
134
|
-
*/
|
|
183
|
+
/** Creates a {@link SharedReadonlyOwner} from a {@link SharedOwner}. */
|
|
135
184
|
export declare const createSharedReadonlyOwner: (sharedOwner: SharedOwner) => SharedReadonlyOwner;
|
|
136
|
-
/** Creates an {@link Owner} with optional `mnemonic` and `writeKey`. */
|
|
137
|
-
export declare const createOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => (mnemonic?: string & import("../Types.js").Brand<"Trimmed"> & import("../Types.js").Brand<"MinLength1"> & import("../Types.js").Brand<"Mnemonic">, writeKey?: WriteKey) => Owner;
|
|
138
|
-
export declare const createWriteKey: (deps: CreateRandomBytesDep) => (seed?: MnemonicSeed) => WriteKey;
|
|
139
|
-
/**
|
|
140
|
-
* An `OwnerRow` represents a row in the `evolu_owner` table, based on an
|
|
141
|
-
* {@link Owner} with an added `timestamp` ({@link TimestampString}) for CRDT
|
|
142
|
-
* sync. It supports all {@link Owner} variants with an optional `writeKey`; use
|
|
143
|
-
* {@link createOwnerRow} to align it with a specific {@link Owner}.
|
|
144
|
-
*/
|
|
145
|
-
export type OwnerRow = Omit<Owner, "writeKey"> & {
|
|
146
|
-
readonly writeKey: WriteKey | null;
|
|
147
|
-
readonly timestamp: TimestampString;
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* Creates an {@link OwnerRow} from any {@link Owner} variant for the
|
|
151
|
-
* `evolu_owner` table, adding a `timestamp` ({@link TimestampString}) for CRDT
|
|
152
|
-
* sync.
|
|
153
|
-
*/
|
|
154
|
-
export declare const createOwnerRow: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep & NanoIdLibDep) => (owner: AppOwner | ShardOwner | SharedOwner | SharedReadonlyOwner) => OwnerRow;
|
|
155
|
-
/**
|
|
156
|
-
* Rotates the {@link WriteKey} for an {@link AppOwner}, {@link ShardOwner}, or
|
|
157
|
-
* {@link SharedOwner}, returning a new instance with the updated key.
|
|
158
|
-
*/
|
|
159
|
-
export declare const rotateWriteKey: <T extends AppOwner | ShardOwner | SharedOwner>(owner: T, newWriteKey: WriteKey) => T;
|
|
160
185
|
//# sourceMappingURL=Owner.d.ts.map
|