@canonmsg/backend-contracts 5.4.0 → 6.0.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/apiErrors.d.ts +1 -0
- package/dist/apiErrors.js +1 -0
- package/dist/canon-verbs.limits.json +2 -1
- package/dist/canon-verbs.schema.json +6 -1
- package/dist/cjs/apiErrors.js +4 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/media.js +6 -0
- package/dist/cjs/verbContract.js +2 -0
- package/dist/cjs/verbSchemas.js +7 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/media.d.ts +6 -0
- package/dist/media.js +6 -0
- package/dist/verbContract.d.ts +7 -1
- package/dist/verbContract.js +2 -0
- package/dist/verbSchemas.d.ts +5 -0
- package/dist/verbSchemas.js +7 -1
- package/package.json +2 -2
- package/dist/cjs/contactSources.js +0 -45
- package/dist/contactSources.d.ts +0 -31
- package/dist/contactSources.js +0 -41
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MESSAGE_ADMISSION_REQUIRED_CODE: "MESSAGE_ADMISSION_REQUIRED";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const MESSAGE_ADMISSION_REQUIRED_CODE = 'MESSAGE_ADMISSION_REQUIRED';
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"runtimeOptionValue": "^[A-Za-z0-9@_][A-Za-z0-9_.:/@+\\-]{0,255}$",
|
|
65
65
|
"workspaceOptionId": "^[A-Za-z0-9@_][A-Za-z0-9_.:@+\\-]{0,255}$",
|
|
66
66
|
"runtimeHandleKey": "^[A-Za-z0-9_.:-]{1,80}$",
|
|
67
|
-
"runtimeControlId": "^[A-Za-z0-9_-]{1,80}$"
|
|
67
|
+
"runtimeControlId": "^[A-Za-z0-9_-]{1,80}$",
|
|
68
|
+
"resumableUploadId": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
|
|
68
69
|
},
|
|
69
70
|
"byteSemantics": {
|
|
70
71
|
"send_to.text": "utf8_bytes<=messageTextBytes",
|
|
@@ -107,7 +107,12 @@
|
|
|
107
107
|
"url": {
|
|
108
108
|
"type": "string",
|
|
109
109
|
"minLength": 1,
|
|
110
|
-
"description": "Must come from
|
|
110
|
+
"description": "Must come from a canonical Canon upload/finalization response or the GIF picker — server allowlist, fail-closed (functions/src/utils/mediaUploadSafety.ts)."
|
|
111
|
+
},
|
|
112
|
+
"uploadId": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
|
|
115
|
+
"description": "Server-issued resumable identity. Preserve it from finalization so the durable message transaction can validate and retain initially temporary media."
|
|
111
116
|
},
|
|
112
117
|
"mimeType": {
|
|
113
118
|
"type": "string"
|
package/dist/cjs/index.js
CHANGED
|
@@ -24,11 +24,11 @@ __exportStar(require("./turnProtocol.js"), exports);
|
|
|
24
24
|
__exportStar(require("./agentBehaviorPolicy.js"), exports);
|
|
25
25
|
__exportStar(require("./agentSearch.js"), exports);
|
|
26
26
|
__exportStar(require("./contactRequest.js"), exports);
|
|
27
|
-
__exportStar(require("./contactSources.js"), exports);
|
|
28
27
|
__exportStar(require("./verbContract.js"), exports);
|
|
29
28
|
__exportStar(require("./verbSchemas.js"), exports);
|
|
30
29
|
__exportStar(require("./verbWire.js"), exports);
|
|
31
30
|
__exportStar(require("./accessPolicy.js"), exports);
|
|
31
|
+
__exportStar(require("./apiErrors.js"), exports);
|
|
32
32
|
__exportStar(require("./firestoreValues.js"), exports);
|
|
33
33
|
__exportStar(require("./moderation.js"), exports);
|
|
34
34
|
__exportStar(require("./selfContext.js"), exports);
|
package/dist/cjs/media.js
CHANGED
|
@@ -83,6 +83,11 @@ function normalizeStoredAttachments(value) {
|
|
|
83
83
|
if (typeof candidate.url !== 'string' || candidate.url.length === 0) {
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
|
+
if (candidate.uploadId !== undefined
|
|
87
|
+
&& (typeof candidate.uploadId !== 'string'
|
|
88
|
+
|| !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(candidate.uploadId))) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
86
91
|
const sizeBytes = normalizeAttachmentNumber(candidate.sizeBytes);
|
|
87
92
|
const width = normalizeAttachmentNumber(candidate.width);
|
|
88
93
|
const height = normalizeAttachmentNumber(candidate.height);
|
|
@@ -90,6 +95,7 @@ function normalizeStoredAttachments(value) {
|
|
|
90
95
|
attachments.push({
|
|
91
96
|
kind: candidate.kind,
|
|
92
97
|
url: candidate.url,
|
|
98
|
+
...(candidate.uploadId ? { uploadId: candidate.uploadId } : {}),
|
|
93
99
|
...(typeof candidate.mimeType === 'string' && candidate.mimeType ? { mimeType: candidate.mimeType } : {}),
|
|
94
100
|
...(typeof candidate.fileName === 'string' && candidate.fileName ? { fileName: candidate.fileName } : {}),
|
|
95
101
|
...(sizeBytes !== undefined ? { sizeBytes } : {}),
|
package/dist/cjs/verbContract.js
CHANGED
|
@@ -82,6 +82,8 @@ exports.VERB_ID_PATTERNS = {
|
|
|
82
82
|
workspaceOptionId: '^[A-Za-z0-9@_][A-Za-z0-9_.:@+\\-]{0,255}$',
|
|
83
83
|
runtimeHandleKey: '^[A-Za-z0-9_.:-]{1,80}$',
|
|
84
84
|
runtimeControlId: '^[A-Za-z0-9_-]{1,80}$',
|
|
85
|
+
/** UUID issued by Canon's resumable-media session endpoint. */
|
|
86
|
+
resumableUploadId: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$',
|
|
85
87
|
};
|
|
86
88
|
/**
|
|
87
89
|
* Server-enforced limits, single-sourced. Each value cites its enforcement
|
package/dist/cjs/verbSchemas.js
CHANGED
|
@@ -93,9 +93,15 @@ const mediaAttachmentDef = {
|
|
|
93
93
|
url: {
|
|
94
94
|
type: 'string',
|
|
95
95
|
minLength: 1,
|
|
96
|
-
description: 'Must come from
|
|
96
|
+
description: 'Must come from a canonical Canon upload/finalization response or the GIF picker — server '
|
|
97
97
|
+ 'allowlist, fail-closed (functions/src/utils/mediaUploadSafety.ts).',
|
|
98
98
|
},
|
|
99
|
+
uploadId: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
pattern: verbContract_js_1.VERB_ID_PATTERNS.resumableUploadId,
|
|
102
|
+
description: 'Server-issued resumable identity. Preserve it from finalization so the durable message '
|
|
103
|
+
+ 'transaction can validate and retain initially temporary media.',
|
|
104
|
+
},
|
|
99
105
|
mimeType: { type: 'string' },
|
|
100
106
|
fileName: { type: 'string' },
|
|
101
107
|
sizeBytes: { type: 'number', minimum: 0 },
|
package/dist/index.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ export * from './turnProtocol.js';
|
|
|
8
8
|
export * from './agentBehaviorPolicy.js';
|
|
9
9
|
export * from './agentSearch.js';
|
|
10
10
|
export * from './contactRequest.js';
|
|
11
|
-
export * from './contactSources.js';
|
|
12
11
|
export * from './verbContract.js';
|
|
13
12
|
export * from './verbSchemas.js';
|
|
14
13
|
export * from './verbWire.js';
|
|
15
14
|
export * from './accessPolicy.js';
|
|
15
|
+
export * from './apiErrors.js';
|
|
16
16
|
export * from './firestoreValues.js';
|
|
17
17
|
export * from './moderation.js';
|
|
18
18
|
export * from './selfContext.js';
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,11 @@ export * from './turnProtocol.js';
|
|
|
8
8
|
export * from './agentBehaviorPolicy.js';
|
|
9
9
|
export * from './agentSearch.js';
|
|
10
10
|
export * from './contactRequest.js';
|
|
11
|
-
export * from './contactSources.js';
|
|
12
11
|
export * from './verbContract.js';
|
|
13
12
|
export * from './verbSchemas.js';
|
|
14
13
|
export * from './verbWire.js';
|
|
15
14
|
export * from './accessPolicy.js';
|
|
15
|
+
export * from './apiErrors.js';
|
|
16
16
|
export * from './firestoreValues.js';
|
|
17
17
|
export * from './moderation.js';
|
|
18
18
|
export * from './selfContext.js';
|
package/dist/media.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ export type MediaAttachmentKind = 'image' | 'audio' | 'video' | 'file';
|
|
|
2
2
|
export interface MediaAttachment {
|
|
3
3
|
kind: MediaAttachmentKind;
|
|
4
4
|
url: string;
|
|
5
|
+
/**
|
|
6
|
+
* Server-issued identity for a finalized resumable upload. The send path
|
|
7
|
+
* uses this to retain temporary canonical media atomically with the message.
|
|
8
|
+
* Legacy/base64 uploads intentionally omit it.
|
|
9
|
+
*/
|
|
10
|
+
uploadId?: string;
|
|
5
11
|
mimeType?: string;
|
|
6
12
|
fileName?: string;
|
|
7
13
|
sizeBytes?: number;
|
package/dist/media.js
CHANGED
|
@@ -75,6 +75,11 @@ export function normalizeStoredAttachments(value) {
|
|
|
75
75
|
if (typeof candidate.url !== 'string' || candidate.url.length === 0) {
|
|
76
76
|
return null;
|
|
77
77
|
}
|
|
78
|
+
if (candidate.uploadId !== undefined
|
|
79
|
+
&& (typeof candidate.uploadId !== 'string'
|
|
80
|
+
|| !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(candidate.uploadId))) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
78
83
|
const sizeBytes = normalizeAttachmentNumber(candidate.sizeBytes);
|
|
79
84
|
const width = normalizeAttachmentNumber(candidate.width);
|
|
80
85
|
const height = normalizeAttachmentNumber(candidate.height);
|
|
@@ -82,6 +87,7 @@ export function normalizeStoredAttachments(value) {
|
|
|
82
87
|
attachments.push({
|
|
83
88
|
kind: candidate.kind,
|
|
84
89
|
url: candidate.url,
|
|
90
|
+
...(candidate.uploadId ? { uploadId: candidate.uploadId } : {}),
|
|
85
91
|
...(typeof candidate.mimeType === 'string' && candidate.mimeType ? { mimeType: candidate.mimeType } : {}),
|
|
86
92
|
...(typeof candidate.fileName === 'string' && candidate.fileName ? { fileName: candidate.fileName } : {}),
|
|
87
93
|
...(sizeBytes !== undefined ? { sizeBytes } : {}),
|
package/dist/verbContract.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ export declare const VERB_ID_PATTERNS: {
|
|
|
77
77
|
readonly workspaceOptionId: "^[A-Za-z0-9@_][A-Za-z0-9_.:@+\\-]{0,255}$";
|
|
78
78
|
readonly runtimeHandleKey: "^[A-Za-z0-9_.:-]{1,80}$";
|
|
79
79
|
readonly runtimeControlId: "^[A-Za-z0-9_-]{1,80}$";
|
|
80
|
+
/** UUID issued by Canon's resumable-media session endpoint. */
|
|
81
|
+
readonly resumableUploadId: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
|
|
80
82
|
};
|
|
81
83
|
/**
|
|
82
84
|
* Server-enforced limits, single-sourced. Each value cites its enforcement
|
|
@@ -246,8 +248,10 @@ export declare const VERB_NATIVE_METADATA_KEYS: readonly ["runtime", "method", "
|
|
|
246
248
|
export declare function normalizeVerbNativeMetadata(value: unknown): VerbNativeMetadata | undefined;
|
|
247
249
|
export interface VerbMediaAttachment {
|
|
248
250
|
kind: 'image' | 'audio' | 'video' | 'file';
|
|
249
|
-
/** Must come from
|
|
251
|
+
/** Must come from a canonical Canon upload/finalization response or the GIF picker. */
|
|
250
252
|
url: string;
|
|
253
|
+
/** Server-issued resumable identity; preserve it so durable sends retain temporary media. */
|
|
254
|
+
uploadId?: string;
|
|
251
255
|
mimeType?: string;
|
|
252
256
|
fileName?: string;
|
|
253
257
|
sizeBytes?: number;
|
|
@@ -846,6 +850,8 @@ export declare const CANON_VERB_LIMITS_ARTIFACT: {
|
|
|
846
850
|
readonly workspaceOptionId: "^[A-Za-z0-9@_][A-Za-z0-9_.:@+\\-]{0,255}$";
|
|
847
851
|
readonly runtimeHandleKey: "^[A-Za-z0-9_.:-]{1,80}$";
|
|
848
852
|
readonly runtimeControlId: "^[A-Za-z0-9_-]{1,80}$";
|
|
853
|
+
/** UUID issued by Canon's resumable-media session endpoint. */
|
|
854
|
+
readonly resumableUploadId: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
|
|
849
855
|
};
|
|
850
856
|
readonly byteSemantics: {
|
|
851
857
|
readonly 'send_to.text': "utf8_bytes<=messageTextBytes";
|
package/dist/verbContract.js
CHANGED
|
@@ -76,6 +76,8 @@ export const VERB_ID_PATTERNS = {
|
|
|
76
76
|
workspaceOptionId: '^[A-Za-z0-9@_][A-Za-z0-9_.:@+\\-]{0,255}$',
|
|
77
77
|
runtimeHandleKey: '^[A-Za-z0-9_.:-]{1,80}$',
|
|
78
78
|
runtimeControlId: '^[A-Za-z0-9_-]{1,80}$',
|
|
79
|
+
/** UUID issued by Canon's resumable-media session endpoint. */
|
|
80
|
+
resumableUploadId: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$',
|
|
79
81
|
};
|
|
80
82
|
/**
|
|
81
83
|
* Server-enforced limits, single-sourced. Each value cites its enforcement
|
package/dist/verbSchemas.d.ts
CHANGED
|
@@ -253,6 +253,11 @@ export declare const CANON_VERBS_JSON_SCHEMA: {
|
|
|
253
253
|
readonly minLength: 1;
|
|
254
254
|
readonly description: string;
|
|
255
255
|
};
|
|
256
|
+
readonly uploadId: {
|
|
257
|
+
readonly type: "string";
|
|
258
|
+
readonly pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
|
|
259
|
+
readonly description: string;
|
|
260
|
+
};
|
|
256
261
|
readonly mimeType: {
|
|
257
262
|
readonly type: "string";
|
|
258
263
|
};
|
package/dist/verbSchemas.js
CHANGED
|
@@ -88,9 +88,15 @@ const mediaAttachmentDef = {
|
|
|
88
88
|
url: {
|
|
89
89
|
type: 'string',
|
|
90
90
|
minLength: 1,
|
|
91
|
-
description: 'Must come from
|
|
91
|
+
description: 'Must come from a canonical Canon upload/finalization response or the GIF picker — server '
|
|
92
92
|
+ 'allowlist, fail-closed (functions/src/utils/mediaUploadSafety.ts).',
|
|
93
93
|
},
|
|
94
|
+
uploadId: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
pattern: VERB_ID_PATTERNS.resumableUploadId,
|
|
97
|
+
description: 'Server-issued resumable identity. Preserve it from finalization so the durable message '
|
|
98
|
+
+ 'transaction can validate and retain initially temporary media.',
|
|
99
|
+
},
|
|
94
100
|
mimeType: { type: 'string' },
|
|
95
101
|
fileName: { type: 'string' },
|
|
96
102
|
sizeBytes: { type: 'number', minimum: 0 },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/backend-contracts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Canon backend contract helpers shared by Functions and stream-service",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@canonmsg/rich-cards": "^0.
|
|
46
|
+
"@canonmsg/rich-cards": "^0.10.2",
|
|
47
47
|
"@types/node": "^22.0.0",
|
|
48
48
|
"ajv": "^8.20.0",
|
|
49
49
|
"typescript": "~5.7.0",
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ADMISSION_GRANTING_SOURCES = void 0;
|
|
4
|
-
exports.isAdmissionGrantingContactSource = isAdmissionGrantingContactSource;
|
|
5
|
-
/**
|
|
6
|
-
* Sources that represent a user-initiated relationship which grants admission
|
|
7
|
-
* past `inboundPolicy: 'approval-required'` and
|
|
8
|
-
* `groupJoinPolicy: 'approval-required'`.
|
|
9
|
-
*
|
|
10
|
-
* - `contact_request`: an explicit approval flow.
|
|
11
|
-
* - `direct_add`: the user added the other side directly.
|
|
12
|
-
* - `link` / `qr`: out-of-band invitations that imply consent.
|
|
13
|
-
* - `group`: established by being in a shared group.
|
|
14
|
-
* - `phone_book`: included intentionally — if a human has a registered Canon
|
|
15
|
-
* user in their device contacts, that is enough to start a human-human DM
|
|
16
|
-
* without a separate Canon request.
|
|
17
|
-
* - `open_inbound_message`: the unified source written when a delivered direct
|
|
18
|
-
* interaction reaches an `inboundPolicy: 'open'` recipient. The recipient
|
|
19
|
-
* consented to open inbound; the resulting mutual contact is real.
|
|
20
|
-
*
|
|
21
|
-
* Hard caps (`owner-only`, blocks, inactive agent) override admission grants
|
|
22
|
-
* regardless of source — ordering lives in `functions/src/utils/access.ts`
|
|
23
|
-
* (`evaluatePolicy` / `buildPolicyContext`).
|
|
24
|
-
*/
|
|
25
|
-
const ADMISSION_GRANTING_CONTACT_SOURCES = [
|
|
26
|
-
'contact_request',
|
|
27
|
-
'direct_add',
|
|
28
|
-
'link',
|
|
29
|
-
'qr',
|
|
30
|
-
'group',
|
|
31
|
-
'phone_book',
|
|
32
|
-
'open_inbound_message',
|
|
33
|
-
];
|
|
34
|
-
exports.ADMISSION_GRANTING_SOURCES = new Set(ADMISSION_GRANTING_CONTACT_SOURCES);
|
|
35
|
-
/**
|
|
36
|
-
* Returns true if a contact-doc source counts as an admission-granting
|
|
37
|
-
* relationship. `null` / `undefined` (no doc, or doc with a missing source)
|
|
38
|
-
* both return `false` — every contact doc must have an explicit source after
|
|
39
|
-
* the cleanup.
|
|
40
|
-
*/
|
|
41
|
-
function isAdmissionGrantingContactSource(source) {
|
|
42
|
-
if (source === null || source === undefined)
|
|
43
|
-
return false;
|
|
44
|
-
return exports.ADMISSION_GRANTING_SOURCES.has(source);
|
|
45
|
-
}
|
package/dist/contactSources.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sources that represent a user-initiated relationship which grants admission
|
|
3
|
-
* past `inboundPolicy: 'approval-required'` and
|
|
4
|
-
* `groupJoinPolicy: 'approval-required'`.
|
|
5
|
-
*
|
|
6
|
-
* - `contact_request`: an explicit approval flow.
|
|
7
|
-
* - `direct_add`: the user added the other side directly.
|
|
8
|
-
* - `link` / `qr`: out-of-band invitations that imply consent.
|
|
9
|
-
* - `group`: established by being in a shared group.
|
|
10
|
-
* - `phone_book`: included intentionally — if a human has a registered Canon
|
|
11
|
-
* user in their device contacts, that is enough to start a human-human DM
|
|
12
|
-
* without a separate Canon request.
|
|
13
|
-
* - `open_inbound_message`: the unified source written when a delivered direct
|
|
14
|
-
* interaction reaches an `inboundPolicy: 'open'` recipient. The recipient
|
|
15
|
-
* consented to open inbound; the resulting mutual contact is real.
|
|
16
|
-
*
|
|
17
|
-
* Hard caps (`owner-only`, blocks, inactive agent) override admission grants
|
|
18
|
-
* regardless of source — ordering lives in `functions/src/utils/access.ts`
|
|
19
|
-
* (`evaluatePolicy` / `buildPolicyContext`).
|
|
20
|
-
*/
|
|
21
|
-
declare const ADMISSION_GRANTING_CONTACT_SOURCES: readonly ["contact_request", "direct_add", "link", "qr", "group", "phone_book", "open_inbound_message"];
|
|
22
|
-
export type AdmissionGrantingContactSource = (typeof ADMISSION_GRANTING_CONTACT_SOURCES)[number];
|
|
23
|
-
export declare const ADMISSION_GRANTING_SOURCES: ReadonlySet<AdmissionGrantingContactSource>;
|
|
24
|
-
/**
|
|
25
|
-
* Returns true if a contact-doc source counts as an admission-granting
|
|
26
|
-
* relationship. `null` / `undefined` (no doc, or doc with a missing source)
|
|
27
|
-
* both return `false` — every contact doc must have an explicit source after
|
|
28
|
-
* the cleanup.
|
|
29
|
-
*/
|
|
30
|
-
export declare function isAdmissionGrantingContactSource(source: string | null | undefined): boolean;
|
|
31
|
-
export {};
|
package/dist/contactSources.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sources that represent a user-initiated relationship which grants admission
|
|
3
|
-
* past `inboundPolicy: 'approval-required'` and
|
|
4
|
-
* `groupJoinPolicy: 'approval-required'`.
|
|
5
|
-
*
|
|
6
|
-
* - `contact_request`: an explicit approval flow.
|
|
7
|
-
* - `direct_add`: the user added the other side directly.
|
|
8
|
-
* - `link` / `qr`: out-of-band invitations that imply consent.
|
|
9
|
-
* - `group`: established by being in a shared group.
|
|
10
|
-
* - `phone_book`: included intentionally — if a human has a registered Canon
|
|
11
|
-
* user in their device contacts, that is enough to start a human-human DM
|
|
12
|
-
* without a separate Canon request.
|
|
13
|
-
* - `open_inbound_message`: the unified source written when a delivered direct
|
|
14
|
-
* interaction reaches an `inboundPolicy: 'open'` recipient. The recipient
|
|
15
|
-
* consented to open inbound; the resulting mutual contact is real.
|
|
16
|
-
*
|
|
17
|
-
* Hard caps (`owner-only`, blocks, inactive agent) override admission grants
|
|
18
|
-
* regardless of source — ordering lives in `functions/src/utils/access.ts`
|
|
19
|
-
* (`evaluatePolicy` / `buildPolicyContext`).
|
|
20
|
-
*/
|
|
21
|
-
const ADMISSION_GRANTING_CONTACT_SOURCES = [
|
|
22
|
-
'contact_request',
|
|
23
|
-
'direct_add',
|
|
24
|
-
'link',
|
|
25
|
-
'qr',
|
|
26
|
-
'group',
|
|
27
|
-
'phone_book',
|
|
28
|
-
'open_inbound_message',
|
|
29
|
-
];
|
|
30
|
-
export const ADMISSION_GRANTING_SOURCES = new Set(ADMISSION_GRANTING_CONTACT_SOURCES);
|
|
31
|
-
/**
|
|
32
|
-
* Returns true if a contact-doc source counts as an admission-granting
|
|
33
|
-
* relationship. `null` / `undefined` (no doc, or doc with a missing source)
|
|
34
|
-
* both return `false` — every contact doc must have an explicit source after
|
|
35
|
-
* the cleanup.
|
|
36
|
-
*/
|
|
37
|
-
export function isAdmissionGrantingContactSource(source) {
|
|
38
|
-
if (source === null || source === undefined)
|
|
39
|
-
return false;
|
|
40
|
-
return ADMISSION_GRANTING_SOURCES.has(source);
|
|
41
|
-
}
|