@anuma/sdk 10.7.0 → 10.8.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/expo/index.cjs +23 -1
- package/dist/expo/index.d.mts +161 -153
- package/dist/expo/index.d.ts +161 -153
- package/dist/expo/index.mjs +23 -1
- package/dist/index.d.mts +157 -153
- package/dist/index.d.ts +157 -153
- package/dist/react/index.cjs +23 -1
- package/dist/react/index.d.mts +161 -153
- package/dist/react/index.d.ts +161 -153
- package/dist/react/index.mjs +23 -1
- package/dist/server/index.d.mts +8 -0
- package/dist/server/index.d.ts +8 -0
- package/package.json +1 -1
package/dist/expo/index.d.ts
CHANGED
|
@@ -3067,6 +3067,159 @@ declare function createWebSearchPreProcessor(options?: WebSearchPreProcessorOpti
|
|
|
3067
3067
|
*/
|
|
3068
3068
|
declare const xhrTransport: StreamingTransport;
|
|
3069
3069
|
|
|
3070
|
+
type ChatRecordKind = "conversation" | "message" | "summary" | "project" | "memory_links" | "setting";
|
|
3071
|
+
type ChatJson = null | boolean | number | string | ChatJson[] | {
|
|
3072
|
+
[key: string]: ChatJson;
|
|
3073
|
+
};
|
|
3074
|
+
/** Whole-record JSON data is encrypted on the device, including all text, vectors and tool events. */
|
|
3075
|
+
interface ChatRecord {
|
|
3076
|
+
kind: ChatRecordKind;
|
|
3077
|
+
id: string;
|
|
3078
|
+
conversationId: string;
|
|
3079
|
+
sortKey: number;
|
|
3080
|
+
createdAt: number;
|
|
3081
|
+
updatedAt: number;
|
|
3082
|
+
isDeleted: boolean;
|
|
3083
|
+
data: {
|
|
3084
|
+
[key: string]: ChatJson;
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
interface ChatSnapshot {
|
|
3088
|
+
record: ChatRecord;
|
|
3089
|
+
version: number;
|
|
3090
|
+
serverUpdatedAt: string;
|
|
3091
|
+
}
|
|
3092
|
+
interface ChatWrite {
|
|
3093
|
+
record: ChatRecord;
|
|
3094
|
+
expectedVersion: number;
|
|
3095
|
+
/** Sent and stored unencrypted so vault can run vector search. */
|
|
3096
|
+
embeddings?: number[][];
|
|
3097
|
+
embeddingModel?: string;
|
|
3098
|
+
}
|
|
3099
|
+
interface ChatRef {
|
|
3100
|
+
kind: ChatRecordKind;
|
|
3101
|
+
id: string;
|
|
3102
|
+
}
|
|
3103
|
+
type ChatAccountState = "none" | "migrating" | "active";
|
|
3104
|
+
interface ChatAccount {
|
|
3105
|
+
keyId: string;
|
|
3106
|
+
state: ChatAccountState;
|
|
3107
|
+
recordCount: number;
|
|
3108
|
+
storageBytes: number;
|
|
3109
|
+
vectorCount: number;
|
|
3110
|
+
/** The newest change; read it before loading history and poll `changes` from it. Absent before the first record. */
|
|
3111
|
+
changesCursor?: string;
|
|
3112
|
+
}
|
|
3113
|
+
interface ChatImport {
|
|
3114
|
+
record: ChatRecord;
|
|
3115
|
+
/** Sent and stored unencrypted so vault can run vector search. */
|
|
3116
|
+
embeddings?: number[][];
|
|
3117
|
+
embeddingModel?: string;
|
|
3118
|
+
}
|
|
3119
|
+
interface ChatRevision {
|
|
3120
|
+
kind: ChatRecordKind;
|
|
3121
|
+
id: string;
|
|
3122
|
+
updatedAt: number;
|
|
3123
|
+
isDeleted: boolean;
|
|
3124
|
+
}
|
|
3125
|
+
interface ChatChanges {
|
|
3126
|
+
items: ChatSnapshot[];
|
|
3127
|
+
nextCursor?: string;
|
|
3128
|
+
changesCursor: string;
|
|
3129
|
+
}
|
|
3130
|
+
interface ChatSearchOptions {
|
|
3131
|
+
limit?: number;
|
|
3132
|
+
kinds?: ("message" | "summary")[];
|
|
3133
|
+
conversationId?: string;
|
|
3134
|
+
excludeConversationId?: string;
|
|
3135
|
+
/** Ranks only vectors from this model; vectors stored without one always count. */
|
|
3136
|
+
embeddingModel?: string;
|
|
3137
|
+
signal?: AbortSignal;
|
|
3138
|
+
}
|
|
3139
|
+
interface ChatSearchHit extends ChatSnapshot {
|
|
3140
|
+
chunk: number;
|
|
3141
|
+
score: number;
|
|
3142
|
+
}
|
|
3143
|
+
interface ChatAttachment {
|
|
3144
|
+
id: string;
|
|
3145
|
+
sizeBytes: number;
|
|
3146
|
+
state: "pending" | "committed";
|
|
3147
|
+
ownerKind?: "message" | "summary";
|
|
3148
|
+
ownerId?: string;
|
|
3149
|
+
createdAt: string;
|
|
3150
|
+
committedAt?: string;
|
|
3151
|
+
}
|
|
3152
|
+
interface ChatPresignedUrl {
|
|
3153
|
+
url: string;
|
|
3154
|
+
method: string;
|
|
3155
|
+
headers: Record<string, string>;
|
|
3156
|
+
expiresAt: string;
|
|
3157
|
+
}
|
|
3158
|
+
interface ChatAttachments {
|
|
3159
|
+
create(sizeBytes: number, signal?: AbortSignal): Promise<{
|
|
3160
|
+
attachment: ChatAttachment;
|
|
3161
|
+
upload: ChatPresignedUrl;
|
|
3162
|
+
}>;
|
|
3163
|
+
commit(attachmentId: string, owner: {
|
|
3164
|
+
kind: "message" | "summary";
|
|
3165
|
+
id: string;
|
|
3166
|
+
}, signal?: AbortSignal): Promise<ChatAttachment>;
|
|
3167
|
+
get(attachmentId: string, signal?: AbortSignal): Promise<{
|
|
3168
|
+
attachment: ChatAttachment;
|
|
3169
|
+
download?: ChatPresignedUrl;
|
|
3170
|
+
} | null>;
|
|
3171
|
+
delete(attachmentId: string, signal?: AbortSignal): Promise<void>;
|
|
3172
|
+
}
|
|
3173
|
+
interface ChatListOptions {
|
|
3174
|
+
kind: ChatRecordKind;
|
|
3175
|
+
conversationId?: string;
|
|
3176
|
+
includeDeleted?: boolean;
|
|
3177
|
+
cursor?: string;
|
|
3178
|
+
limit?: number;
|
|
3179
|
+
signal?: AbortSignal;
|
|
3180
|
+
}
|
|
3181
|
+
interface ChatPage {
|
|
3182
|
+
items: ChatSnapshot[];
|
|
3183
|
+
nextCursor?: string;
|
|
3184
|
+
total?: number;
|
|
3185
|
+
}
|
|
3186
|
+
/** Explicit versions protect edits; ambiguous writes are never replayed automatically. */
|
|
3187
|
+
interface ChatStore {
|
|
3188
|
+
get(kind: ChatRecordKind, id: string, signal?: AbortSignal): Promise<ChatSnapshot | null>;
|
|
3189
|
+
list(options: ChatListOptions): Promise<ChatPage>;
|
|
3190
|
+
putMany(writes: readonly ChatWrite[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
|
|
3191
|
+
getMany(refs: readonly ChatRef[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
|
|
3192
|
+
account(signal?: AbortSignal): Promise<ChatAccount>;
|
|
3193
|
+
importRecords(records: readonly ChatImport[], signal?: AbortSignal): Promise<number>;
|
|
3194
|
+
verify(revisions: readonly ChatRevision[], signal?: AbortSignal): Promise<ChatRef[]>;
|
|
3195
|
+
activate(signal?: AbortSignal): Promise<boolean>;
|
|
3196
|
+
/** Without `kinds`, vault returns every kind except `setting`. */
|
|
3197
|
+
changes(cursor?: string, options?: {
|
|
3198
|
+
limit?: number;
|
|
3199
|
+
kinds?: readonly ChatRecordKind[];
|
|
3200
|
+
signal?: AbortSignal;
|
|
3201
|
+
}): Promise<ChatChanges>;
|
|
3202
|
+
search(embedding: readonly number[], options?: ChatSearchOptions): Promise<ChatSearchHit[]>;
|
|
3203
|
+
deleteAll(signal?: AbortSignal): Promise<number>;
|
|
3204
|
+
attachments: ChatAttachments;
|
|
3205
|
+
}
|
|
3206
|
+
interface RemoteChatStoreOptions {
|
|
3207
|
+
baseUrl: string;
|
|
3208
|
+
getToken: () => Promise<string | null>;
|
|
3209
|
+
keyId: string;
|
|
3210
|
+
encrypt: (plaintext: string) => Promise<string>;
|
|
3211
|
+
decrypt: (ciphertext: string) => Promise<string>;
|
|
3212
|
+
fetch?: typeof globalThis.fetch;
|
|
3213
|
+
timeoutMs?: number;
|
|
3214
|
+
signal?: AbortSignal;
|
|
3215
|
+
}
|
|
3216
|
+
declare class ChatStoreError extends Error {
|
|
3217
|
+
readonly status: number;
|
|
3218
|
+
readonly code?: string | undefined;
|
|
3219
|
+
readonly retryAfterMs?: number | undefined;
|
|
3220
|
+
constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3070
3223
|
declare class VaultMemory extends Model {
|
|
3071
3224
|
static table: string;
|
|
3072
3225
|
content: string;
|
|
@@ -7537,6 +7690,10 @@ interface StoredConversation {
|
|
|
7537
7690
|
/** When the conversation was pinned to the top of the list; null/unset = not pinned.
|
|
7538
7691
|
* `null` (not `undefined`) at runtime for unpinned rows — mirrors the model field. */
|
|
7539
7692
|
pinnedAt?: Date | null;
|
|
7693
|
+
/** Per-conversation app state kept with the conversation in vault, keyed by the app; absent on local storage. */
|
|
7694
|
+
context?: {
|
|
7695
|
+
[key: string]: ChatJson;
|
|
7696
|
+
};
|
|
7540
7697
|
}
|
|
7541
7698
|
/**
|
|
7542
7699
|
* Lazy variant of {@link StoredConversation}.
|
|
@@ -8275,159 +8432,6 @@ interface BaseUseChatStorageResult {
|
|
|
8275
8432
|
}
|
|
8276
8433
|
declare function generateConversationId(): string;
|
|
8277
8434
|
|
|
8278
|
-
type ChatRecordKind = "conversation" | "message" | "summary" | "project" | "memory_links" | "setting";
|
|
8279
|
-
type ChatJson = null | boolean | number | string | ChatJson[] | {
|
|
8280
|
-
[key: string]: ChatJson;
|
|
8281
|
-
};
|
|
8282
|
-
/** Whole-record JSON data is encrypted on the device, including all text, vectors and tool events. */
|
|
8283
|
-
interface ChatRecord {
|
|
8284
|
-
kind: ChatRecordKind;
|
|
8285
|
-
id: string;
|
|
8286
|
-
conversationId: string;
|
|
8287
|
-
sortKey: number;
|
|
8288
|
-
createdAt: number;
|
|
8289
|
-
updatedAt: number;
|
|
8290
|
-
isDeleted: boolean;
|
|
8291
|
-
data: {
|
|
8292
|
-
[key: string]: ChatJson;
|
|
8293
|
-
};
|
|
8294
|
-
}
|
|
8295
|
-
interface ChatSnapshot {
|
|
8296
|
-
record: ChatRecord;
|
|
8297
|
-
version: number;
|
|
8298
|
-
serverUpdatedAt: string;
|
|
8299
|
-
}
|
|
8300
|
-
interface ChatWrite {
|
|
8301
|
-
record: ChatRecord;
|
|
8302
|
-
expectedVersion: number;
|
|
8303
|
-
/** Sent and stored unencrypted so vault can run vector search. */
|
|
8304
|
-
embeddings?: number[][];
|
|
8305
|
-
embeddingModel?: string;
|
|
8306
|
-
}
|
|
8307
|
-
interface ChatRef {
|
|
8308
|
-
kind: ChatRecordKind;
|
|
8309
|
-
id: string;
|
|
8310
|
-
}
|
|
8311
|
-
type ChatAccountState = "none" | "migrating" | "active";
|
|
8312
|
-
interface ChatAccount {
|
|
8313
|
-
keyId: string;
|
|
8314
|
-
state: ChatAccountState;
|
|
8315
|
-
recordCount: number;
|
|
8316
|
-
storageBytes: number;
|
|
8317
|
-
vectorCount: number;
|
|
8318
|
-
/** The newest change; read it before loading history and poll `changes` from it. Absent before the first record. */
|
|
8319
|
-
changesCursor?: string;
|
|
8320
|
-
}
|
|
8321
|
-
interface ChatImport {
|
|
8322
|
-
record: ChatRecord;
|
|
8323
|
-
/** Sent and stored unencrypted so vault can run vector search. */
|
|
8324
|
-
embeddings?: number[][];
|
|
8325
|
-
embeddingModel?: string;
|
|
8326
|
-
}
|
|
8327
|
-
interface ChatRevision {
|
|
8328
|
-
kind: ChatRecordKind;
|
|
8329
|
-
id: string;
|
|
8330
|
-
updatedAt: number;
|
|
8331
|
-
isDeleted: boolean;
|
|
8332
|
-
}
|
|
8333
|
-
interface ChatChanges {
|
|
8334
|
-
items: ChatSnapshot[];
|
|
8335
|
-
nextCursor?: string;
|
|
8336
|
-
changesCursor: string;
|
|
8337
|
-
}
|
|
8338
|
-
interface ChatSearchOptions {
|
|
8339
|
-
limit?: number;
|
|
8340
|
-
kinds?: ("message" | "summary")[];
|
|
8341
|
-
conversationId?: string;
|
|
8342
|
-
excludeConversationId?: string;
|
|
8343
|
-
/** Ranks only vectors from this model; vectors stored without one always count. */
|
|
8344
|
-
embeddingModel?: string;
|
|
8345
|
-
signal?: AbortSignal;
|
|
8346
|
-
}
|
|
8347
|
-
interface ChatSearchHit extends ChatSnapshot {
|
|
8348
|
-
chunk: number;
|
|
8349
|
-
score: number;
|
|
8350
|
-
}
|
|
8351
|
-
interface ChatAttachment {
|
|
8352
|
-
id: string;
|
|
8353
|
-
sizeBytes: number;
|
|
8354
|
-
state: "pending" | "committed";
|
|
8355
|
-
ownerKind?: "message" | "summary";
|
|
8356
|
-
ownerId?: string;
|
|
8357
|
-
createdAt: string;
|
|
8358
|
-
committedAt?: string;
|
|
8359
|
-
}
|
|
8360
|
-
interface ChatPresignedUrl {
|
|
8361
|
-
url: string;
|
|
8362
|
-
method: string;
|
|
8363
|
-
headers: Record<string, string>;
|
|
8364
|
-
expiresAt: string;
|
|
8365
|
-
}
|
|
8366
|
-
interface ChatAttachments {
|
|
8367
|
-
create(sizeBytes: number, signal?: AbortSignal): Promise<{
|
|
8368
|
-
attachment: ChatAttachment;
|
|
8369
|
-
upload: ChatPresignedUrl;
|
|
8370
|
-
}>;
|
|
8371
|
-
commit(attachmentId: string, owner: {
|
|
8372
|
-
kind: "message" | "summary";
|
|
8373
|
-
id: string;
|
|
8374
|
-
}, signal?: AbortSignal): Promise<ChatAttachment>;
|
|
8375
|
-
get(attachmentId: string, signal?: AbortSignal): Promise<{
|
|
8376
|
-
attachment: ChatAttachment;
|
|
8377
|
-
download?: ChatPresignedUrl;
|
|
8378
|
-
} | null>;
|
|
8379
|
-
delete(attachmentId: string, signal?: AbortSignal): Promise<void>;
|
|
8380
|
-
}
|
|
8381
|
-
interface ChatListOptions {
|
|
8382
|
-
kind: ChatRecordKind;
|
|
8383
|
-
conversationId?: string;
|
|
8384
|
-
includeDeleted?: boolean;
|
|
8385
|
-
cursor?: string;
|
|
8386
|
-
limit?: number;
|
|
8387
|
-
signal?: AbortSignal;
|
|
8388
|
-
}
|
|
8389
|
-
interface ChatPage {
|
|
8390
|
-
items: ChatSnapshot[];
|
|
8391
|
-
nextCursor?: string;
|
|
8392
|
-
total?: number;
|
|
8393
|
-
}
|
|
8394
|
-
/** Explicit versions protect edits; ambiguous writes are never replayed automatically. */
|
|
8395
|
-
interface ChatStore {
|
|
8396
|
-
get(kind: ChatRecordKind, id: string, signal?: AbortSignal): Promise<ChatSnapshot | null>;
|
|
8397
|
-
list(options: ChatListOptions): Promise<ChatPage>;
|
|
8398
|
-
putMany(writes: readonly ChatWrite[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
|
|
8399
|
-
getMany(refs: readonly ChatRef[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
|
|
8400
|
-
account(signal?: AbortSignal): Promise<ChatAccount>;
|
|
8401
|
-
importRecords(records: readonly ChatImport[], signal?: AbortSignal): Promise<number>;
|
|
8402
|
-
verify(revisions: readonly ChatRevision[], signal?: AbortSignal): Promise<ChatRef[]>;
|
|
8403
|
-
activate(signal?: AbortSignal): Promise<boolean>;
|
|
8404
|
-
/** Without `kinds`, vault returns every kind except `setting`. */
|
|
8405
|
-
changes(cursor?: string, options?: {
|
|
8406
|
-
limit?: number;
|
|
8407
|
-
kinds?: readonly ChatRecordKind[];
|
|
8408
|
-
signal?: AbortSignal;
|
|
8409
|
-
}): Promise<ChatChanges>;
|
|
8410
|
-
search(embedding: readonly number[], options?: ChatSearchOptions): Promise<ChatSearchHit[]>;
|
|
8411
|
-
deleteAll(signal?: AbortSignal): Promise<number>;
|
|
8412
|
-
attachments: ChatAttachments;
|
|
8413
|
-
}
|
|
8414
|
-
interface RemoteChatStoreOptions {
|
|
8415
|
-
baseUrl: string;
|
|
8416
|
-
getToken: () => Promise<string | null>;
|
|
8417
|
-
keyId: string;
|
|
8418
|
-
encrypt: (plaintext: string) => Promise<string>;
|
|
8419
|
-
decrypt: (ciphertext: string) => Promise<string>;
|
|
8420
|
-
fetch?: typeof globalThis.fetch;
|
|
8421
|
-
timeoutMs?: number;
|
|
8422
|
-
signal?: AbortSignal;
|
|
8423
|
-
}
|
|
8424
|
-
declare class ChatStoreError extends Error {
|
|
8425
|
-
readonly status: number;
|
|
8426
|
-
readonly code?: string | undefined;
|
|
8427
|
-
readonly retryAfterMs?: number | undefined;
|
|
8428
|
-
constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
|
|
8429
|
-
}
|
|
8430
|
-
|
|
8431
8435
|
interface ChatMigrationOptions {
|
|
8432
8436
|
/** The device's local chat database. */
|
|
8433
8437
|
database: Database;
|
|
@@ -8693,6 +8697,10 @@ interface VaultChatBackend extends ChatBackend {
|
|
|
8693
8697
|
conversations: number;
|
|
8694
8698
|
messages: number;
|
|
8695
8699
|
}>;
|
|
8700
|
+
/** Sets keys of a conversation's app context, each saved on its own so devices editing different keys keep both; `null` clears a key. */
|
|
8701
|
+
updateConversationContext(conversationId: string, context: {
|
|
8702
|
+
[key: string]: ChatJson | null;
|
|
8703
|
+
}): Promise<boolean>;
|
|
8696
8704
|
status(): {
|
|
8697
8705
|
pending: number;
|
|
8698
8706
|
stopped?: string;
|
package/dist/expo/index.mjs
CHANGED
|
@@ -10146,9 +10146,23 @@ function conversationSortKey(data, createdAt) {
|
|
|
10146
10146
|
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
10147
10147
|
return number(data.lastActivityAt) ?? createdAt;
|
|
10148
10148
|
}
|
|
10149
|
+
var CONTEXT_FIELD_PREFIX = "context.";
|
|
10150
|
+
function contextField(key3) {
|
|
10151
|
+
return `${CONTEXT_FIELD_PREFIX}${key3}`;
|
|
10152
|
+
}
|
|
10153
|
+
function contextFields(context) {
|
|
10154
|
+
return plain(
|
|
10155
|
+
Object.fromEntries(Object.entries(context ?? {}).map(([k, value]) => [contextField(k), value]))
|
|
10156
|
+
);
|
|
10157
|
+
}
|
|
10158
|
+
function conversationContext(data) {
|
|
10159
|
+
const entries = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
|
|
10160
|
+
return entries.length > 0 ? plain(Object.fromEntries(entries)) : void 0;
|
|
10161
|
+
}
|
|
10149
10162
|
function toConversation(record2) {
|
|
10150
10163
|
const pinnedAt = number(record2.data.pinnedAt);
|
|
10151
10164
|
const projectId = text4(record2.data.projectId);
|
|
10165
|
+
const context = conversationContext(record2.data);
|
|
10152
10166
|
return {
|
|
10153
10167
|
uniqueId: record2.id,
|
|
10154
10168
|
conversationId: record2.id,
|
|
@@ -10157,7 +10171,8 @@ function toConversation(record2) {
|
|
|
10157
10171
|
createdAt: new Date(record2.createdAt),
|
|
10158
10172
|
updatedAt: new Date(record2.updatedAt),
|
|
10159
10173
|
isDeleted: record2.isDeleted,
|
|
10160
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
10174
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
|
|
10175
|
+
...context ? { context } : {}
|
|
10161
10176
|
};
|
|
10162
10177
|
}
|
|
10163
10178
|
function messageData(options) {
|
|
@@ -10316,6 +10331,7 @@ function bytes2(value) {
|
|
|
10316
10331
|
function conversationRecord(conversation, messages) {
|
|
10317
10332
|
const createdAt = ms(conversation.createdAt);
|
|
10318
10333
|
const data = plain({
|
|
10334
|
+
...contextFields(conversation.context),
|
|
10319
10335
|
title: conversation.title,
|
|
10320
10336
|
projectId: conversation.projectId || void 0,
|
|
10321
10337
|
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
@@ -13209,6 +13225,12 @@ function createVaultChatBackend(options) {
|
|
|
13209
13225
|
async updateConversationPinned(conversationId, pinned) {
|
|
13210
13226
|
return updateConversation(conversationId, { pinnedAt: pinned ? now() : null });
|
|
13211
13227
|
},
|
|
13228
|
+
async updateConversationContext(conversationId, context) {
|
|
13229
|
+
const set = contextFields(context);
|
|
13230
|
+
if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
|
|
13231
|
+
const record2 = await conversation(conversationId);
|
|
13232
|
+
return !!record2 && !record2.isDeleted;
|
|
13233
|
+
},
|
|
13212
13234
|
async deleteConversation(conversationId) {
|
|
13213
13235
|
const record2 = await conversation(conversationId);
|
|
13214
13236
|
if (!record2 || record2.isDeleted) return false;
|