@rei-standard/amsg-server 3.0.0 → 3.1.0-next.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/README.md +110 -11
- package/dist/adapters/d1.d.ts +3 -3
- package/dist/adapters/interface.d.ts +6 -3
- package/dist/{chunk-YBDQJVFQ.cjs → chunk-3NIYNYZY.cjs} +221 -83
- package/dist/{chunk-RL7V7VSS.mjs → chunk-6TCZEACV.mjs} +174 -36
- package/dist/cloudflare.cjs +4 -2
- package/dist/cloudflare.d.ts +1 -1
- package/dist/cloudflare.mjs +3 -1
- package/dist/index.cjs +27 -25
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +3 -1
- package/dist/lib/agentic-fire.d.ts +1 -0
- package/dist/lib/attachments.d.ts +39 -0
- package/dist/lib/client-state-store.d.ts +6 -4
- package/dist/lib/state-accessors.d.ts +12 -8
- package/dist/lib/task-projection.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
var _chunk3NIYNYZYcjs = require('./chunk-3NIYNYZY.cjs');
|
|
77
78
|
require('./chunk-7NMQFTDJ.cjs');
|
|
78
79
|
|
|
79
80
|
// src/server/adapters/factory.js
|
|
@@ -107,7 +108,7 @@ async function createAdapter(config) {
|
|
|
107
108
|
// src/server/handlers/init-tenant.js
|
|
108
109
|
function createInitTenantHandler(ctx) {
|
|
109
110
|
async function POST(headers, body) {
|
|
110
|
-
const initSecret =
|
|
111
|
+
const initSecret = _chunk3NIYNYZYcjs.getHeader.call(void 0, headers, "x-init-secret");
|
|
111
112
|
if (ctx.tenant.initSecret && initSecret !== ctx.tenant.initSecret) {
|
|
112
113
|
return {
|
|
113
114
|
status: 401,
|
|
@@ -120,7 +121,7 @@ function createInitTenantHandler(ctx) {
|
|
|
120
121
|
}
|
|
121
122
|
};
|
|
122
123
|
}
|
|
123
|
-
const parsed =
|
|
124
|
+
const parsed = _chunk3NIYNYZYcjs.parseJsonBody.call(void 0, body);
|
|
124
125
|
if (!parsed.ok) {
|
|
125
126
|
return {
|
|
126
127
|
status: 400,
|
|
@@ -134,7 +135,7 @@ function createInitTenantHandler(ctx) {
|
|
|
134
135
|
const tenantId = payload.tenantId || void 0;
|
|
135
136
|
const driver = payload.driver;
|
|
136
137
|
const databaseUrl = payload.databaseUrl || payload.connectionString;
|
|
137
|
-
if (tenantId && !
|
|
138
|
+
if (tenantId && !_chunk3NIYNYZYcjs.isValidUUIDv4.call(void 0, tenantId)) {
|
|
138
139
|
return {
|
|
139
140
|
status: 400,
|
|
140
141
|
body: {
|
|
@@ -254,7 +255,7 @@ function createSendNotificationsHandler(ctx) {
|
|
|
254
255
|
}
|
|
255
256
|
};
|
|
256
257
|
}
|
|
257
|
-
const data = await
|
|
258
|
+
const data = await _chunk3NIYNYZYcjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
|
|
258
259
|
return { status: 200, body: { success: true, data } };
|
|
259
260
|
}
|
|
260
261
|
return { POST };
|
|
@@ -276,16 +277,16 @@ function encryptConfig(config, kekBuffer) {
|
|
|
276
277
|
const plaintext = Buffer.from(JSON.stringify(config), "utf8");
|
|
277
278
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
278
279
|
const authTag = cipher.getAuthTag();
|
|
279
|
-
return `v1.${
|
|
280
|
+
return `v1.${_chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, iv)}.${_chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, authTag)}.${_chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, ciphertext)}`;
|
|
280
281
|
}
|
|
281
282
|
function decryptConfig(encrypted, kekBuffer) {
|
|
282
283
|
const parts = String(encrypted || "").split(".");
|
|
283
284
|
if (parts.length !== 4 || parts[0] !== "v1") {
|
|
284
285
|
throw new Error("INVALID_TENANT_CONFIG");
|
|
285
286
|
}
|
|
286
|
-
const iv =
|
|
287
|
-
const authTag =
|
|
288
|
-
const ciphertext =
|
|
287
|
+
const iv = _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, parts[1]);
|
|
288
|
+
const authTag = _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, parts[2]);
|
|
289
|
+
const ciphertext = _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, parts[3]);
|
|
289
290
|
const decipher = _crypto.createDecipheriv.call(void 0, "aes-256-gcm", kekBuffer, iv);
|
|
290
291
|
decipher.setAuthTag(authTag);
|
|
291
292
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
@@ -353,7 +354,7 @@ function createTenantBlobStore(options) {
|
|
|
353
354
|
// src/server/tenant/token.js
|
|
354
355
|
|
|
355
356
|
function sign(input, secret) {
|
|
356
|
-
return
|
|
357
|
+
return _chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
|
|
357
358
|
}
|
|
358
359
|
function nowEpochSeconds() {
|
|
359
360
|
return Math.floor(Date.now() / 1e3);
|
|
@@ -369,8 +370,8 @@ function createTenantToken(params, secret) {
|
|
|
369
370
|
v: 1
|
|
370
371
|
};
|
|
371
372
|
const header = { alg: "HS256", typ: "JWT" };
|
|
372
|
-
const encodedHeader =
|
|
373
|
-
const encodedPayload =
|
|
373
|
+
const encodedHeader = _chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, _chunk3NIYNYZYcjs.utf8.call(void 0, JSON.stringify(header)));
|
|
374
|
+
const encodedPayload = _chunk3NIYNYZYcjs.bytesToBase64Url.call(void 0, _chunk3NIYNYZYcjs.utf8.call(void 0, JSON.stringify(payload)));
|
|
374
375
|
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
375
376
|
const signature = sign(signingInput, secret);
|
|
376
377
|
return `${signingInput}.${signature}`;
|
|
@@ -389,17 +390,17 @@ function verifyTenantToken(token, secret, options = {}) {
|
|
|
389
390
|
let receivedBytes;
|
|
390
391
|
let expectedBytes;
|
|
391
392
|
try {
|
|
392
|
-
receivedBytes =
|
|
393
|
-
expectedBytes =
|
|
393
|
+
receivedBytes = _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, receivedSignature);
|
|
394
|
+
expectedBytes = _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, expectedSignature);
|
|
394
395
|
} catch (e) {
|
|
395
396
|
throw new Error("INVALID_TENANT_AUTH");
|
|
396
397
|
}
|
|
397
|
-
if (!
|
|
398
|
+
if (!_chunk3NIYNYZYcjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
|
|
398
399
|
throw new Error("INVALID_TENANT_AUTH");
|
|
399
400
|
}
|
|
400
401
|
let payload;
|
|
401
402
|
try {
|
|
402
|
-
payload = JSON.parse(
|
|
403
|
+
payload = JSON.parse(_chunk3NIYNYZYcjs.utf8Decode.call(void 0, _chunk3NIYNYZYcjs.base64UrlToBytes.call(void 0, encodedPayload)));
|
|
403
404
|
} catch (e2) {
|
|
404
405
|
throw new Error("INVALID_TENANT_AUTH");
|
|
405
406
|
}
|
|
@@ -627,15 +628,15 @@ async function createReiServer(config) {
|
|
|
627
628
|
return {
|
|
628
629
|
handlers: {
|
|
629
630
|
initTenant: createInitTenantHandler(ctx),
|
|
630
|
-
getUserKey:
|
|
631
|
-
scheduleMessage:
|
|
631
|
+
getUserKey: _chunk3NIYNYZYcjs.createGetUserKeyHandler.call(void 0, ctx),
|
|
632
|
+
scheduleMessage: _chunk3NIYNYZYcjs.createScheduleMessageHandler.call(void 0, ctx),
|
|
632
633
|
sendNotifications: createSendNotificationsHandler(ctx),
|
|
633
|
-
updateMessage:
|
|
634
|
-
cancelMessage:
|
|
635
|
-
messages:
|
|
636
|
-
getMessage:
|
|
637
|
-
pushSubscription:
|
|
638
|
-
llmCredentials:
|
|
634
|
+
updateMessage: _chunk3NIYNYZYcjs.createUpdateMessageHandler.call(void 0, ctx),
|
|
635
|
+
cancelMessage: _chunk3NIYNYZYcjs.createCancelMessageHandler.call(void 0, ctx),
|
|
636
|
+
messages: _chunk3NIYNYZYcjs.createMessagesHandler.call(void 0, ctx),
|
|
637
|
+
getMessage: _chunk3NIYNYZYcjs.createGetMessageHandler.call(void 0, ctx),
|
|
638
|
+
pushSubscription: _chunk3NIYNYZYcjs.createPushSubscriptionHandler.call(void 0, ctx),
|
|
639
|
+
llmCredentials: _chunk3NIYNYZYcjs.createLlmCredentialsHandler.call(void 0, ctx)
|
|
639
640
|
}
|
|
640
641
|
};
|
|
641
642
|
}
|
|
@@ -703,4 +704,5 @@ async function createReiServer(config) {
|
|
|
703
704
|
|
|
704
705
|
|
|
705
706
|
|
|
706
|
-
|
|
707
|
+
|
|
708
|
+
exports.CORS_ALLOW_HEADERS = _chunk3NIYNYZYcjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunk3NIYNYZYcjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunk3NIYNYZYcjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunk3NIYNYZYcjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunk3NIYNYZYcjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunk3NIYNYZYcjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunk3NIYNYZYcjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunk3NIYNYZYcjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunk3NIYNYZYcjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunk3NIYNYZYcjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunk3NIYNYZYcjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunk3NIYNYZYcjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunk3NIYNYZYcjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunk3NIYNYZYcjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunk3NIYNYZYcjs.DeploymentConfigError; exports.MAX_DEFER_AFTER_MS = _chunk3NIYNYZYcjs.MAX_DEFER_AFTER_MS; exports.MAX_PUSH_PAYLOAD_BYTES = _chunk3NIYNYZYcjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunk3NIYNYZYcjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunk3NIYNYZYcjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunk3NIYNYZYcjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunk3NIYNYZYcjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunk3NIYNYZYcjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunk3NIYNYZYcjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunk3NIYNYZYcjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunk3NIYNYZYcjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunk3NIYNYZYcjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunk3NIYNYZYcjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunk3NIYNYZYcjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunk3NIYNYZYcjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunk3NIYNYZYcjs.decryptFromStorage; exports.decryptPayload = _chunk3NIYNYZYcjs.decryptPayload; exports.deriveUserEncryptionKey = _chunk3NIYNYZYcjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunk3NIYNYZYcjs.encryptForStorage; exports.encryptPayload = _chunk3NIYNYZYcjs.encryptPayload; exports.ensureSchema = _chunk3NIYNYZYcjs.ensureSchema; exports.getSchemaVersion = _chunk3NIYNYZYcjs.getSchemaVersion; exports.hasChatCredRef = _chunk3NIYNYZYcjs.hasChatCredRef; exports.isNonRetryableError = _chunk3NIYNYZYcjs.isNonRetryableError; exports.isValidCredId = _chunk3NIYNYZYcjs.isValidCredId; exports.isValidISO8601 = _chunk3NIYNYZYcjs.isValidISO8601; exports.isValidTimeZoneId = _chunk3NIYNYZYcjs.isValidTimeZoneId; exports.isValidUUID = _chunk3NIYNYZYcjs.isValidUUID; exports.isValidUUIDv4 = _chunk3NIYNYZYcjs.isValidUUIDv4; exports.isValidUrl = _chunk3NIYNYZYcjs.isValidUrl; exports.measurePushPayload = _chunk3NIYNYZYcjs.measurePushPayload; exports.nextFutureOccurrence = _chunk3NIYNYZYcjs.nextFutureOccurrence; exports.planNextOccurrence = _chunk3NIYNYZYcjs.planNextOccurrence; exports.readRequestBody = _chunk3NIYNYZYcjs.readRequestBody; exports.resolveLlmCredential = _chunk3NIYNYZYcjs.resolveLlmCredential; exports.runScheduledTick = _chunk3NIYNYZYcjs.runScheduledTick; exports.runTask = _chunk3NIYNYZYcjs.runTask; exports.sanitizeErrorSummary = _chunk3NIYNYZYcjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunk3NIYNYZYcjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunk3NIYNYZYcjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunk3NIYNYZYcjs.validateAvatarUrl; exports.validateCredRefs = _chunk3NIYNYZYcjs.validateCredRefs; exports.validateCredValue = _chunk3NIYNYZYcjs.validateCredValue; exports.validateLlmMessagesArray = _chunk3NIYNYZYcjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunk3NIYNYZYcjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunk3NIYNYZYcjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
|
package/dist/index.d.cts
CHANGED
|
@@ -178,7 +178,7 @@ export { getSchemaVersion, ensureSchema, SCHEMA_VERSION } from "./lib/schema-ver
|
|
|
178
178
|
export { DEFAULT_MAX_TOOL_ITERATIONS, DEFAULT_TOTAL_TIMEOUT_MS, DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE, MIN_SCHEDULE_LEAD_MS, MAX_DEFER_AFTER_MS } from "./lib/agentic-fire.js";
|
|
179
179
|
export { CORS_ALLOW_HEADERS, CORS_ALLOW_METHODS, createSingleUserCloudflareWorker } from "./cloudflare/single-user-worker.js";
|
|
180
180
|
export { createWebCryptoWebPush, measurePushPayload, MAX_PUSH_PAYLOAD_BYTES, PUSH_ENVELOPE_RESERVED_BYTES, WEB_PUSH_MAX_BODY_BYTES, WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES } from "./lib/webpush-webcrypto.js";
|
|
181
|
-
export { deriveUserEncryptionKey, decryptPayload, encryptForStorage, decryptFromStorage } from "./lib/encryption.js";
|
|
181
|
+
export { deriveUserEncryptionKey, decryptPayload, encryptPayload, encryptForStorage, decryptFromStorage } from "./lib/encryption.js";
|
|
182
182
|
export { validateScheduleMessagePayload, validateLlmMessagesArray, validateSplitPattern, validateAvatarUrl, isValidISO8601, isValidUrl, isValidUUID, isValidUUIDv4, isValidTimeZoneId, MAX_TASK_PAYLOAD_BYTES } from "./lib/validation.js";
|
|
183
183
|
export { readRequestBody, DEFAULT_MAX_REQUEST_BODY_BYTES } from "./lib/request.js";
|
|
184
184
|
export { supportsLlmCredentialsStore, isValidCredId, validateCredRefs, validateCredValue, hasChatCredRef, resolveLlmCredential, CRED_ID_MAX_LENGTH, CRED_PUT_BATCH_MAX, CRED_ROWS_PER_USER_MAX, CRED_REFS_MAX_ENTRIES } from "./lib/llm-credentials-store.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -178,7 +178,7 @@ export { getSchemaVersion, ensureSchema, SCHEMA_VERSION } from "./lib/schema-ver
|
|
|
178
178
|
export { DEFAULT_MAX_TOOL_ITERATIONS, DEFAULT_TOTAL_TIMEOUT_MS, DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE, MIN_SCHEDULE_LEAD_MS, MAX_DEFER_AFTER_MS } from "./lib/agentic-fire.js";
|
|
179
179
|
export { CORS_ALLOW_HEADERS, CORS_ALLOW_METHODS, createSingleUserCloudflareWorker } from "./cloudflare/single-user-worker.js";
|
|
180
180
|
export { createWebCryptoWebPush, measurePushPayload, MAX_PUSH_PAYLOAD_BYTES, PUSH_ENVELOPE_RESERVED_BYTES, WEB_PUSH_MAX_BODY_BYTES, WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES } from "./lib/webpush-webcrypto.js";
|
|
181
|
-
export { deriveUserEncryptionKey, decryptPayload, encryptForStorage, decryptFromStorage } from "./lib/encryption.js";
|
|
181
|
+
export { deriveUserEncryptionKey, decryptPayload, encryptPayload, encryptForStorage, decryptFromStorage } from "./lib/encryption.js";
|
|
182
182
|
export { validateScheduleMessagePayload, validateLlmMessagesArray, validateSplitPattern, validateAvatarUrl, isValidISO8601, isValidUrl, isValidUUID, isValidUUIDv4, isValidTimeZoneId, MAX_TASK_PAYLOAD_BYTES } from "./lib/validation.js";
|
|
183
183
|
export { readRequestBody, DEFAULT_MAX_REQUEST_BODY_BYTES } from "./lib/request.js";
|
|
184
184
|
export { supportsLlmCredentialsStore, isValidCredId, validateCredRefs, validateCredValue, hasChatCredRef, resolveLlmCredential, CRED_ID_MAX_LENGTH, CRED_PUT_BATCH_MAX, CRED_ROWS_PER_USER_MAX, CRED_REFS_MAX_ENTRIES } from "./lib/llm-credentials-store.js";
|
package/dist/index.mjs
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
decryptPayload,
|
|
43
43
|
deriveUserEncryptionKey,
|
|
44
44
|
encryptForStorage,
|
|
45
|
+
encryptPayload,
|
|
45
46
|
ensureSchema,
|
|
46
47
|
getHeader,
|
|
47
48
|
getSchemaVersion,
|
|
@@ -73,7 +74,7 @@ import {
|
|
|
73
74
|
validateLlmMessagesArray,
|
|
74
75
|
validateScheduleMessagePayload,
|
|
75
76
|
validateSplitPattern
|
|
76
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-6TCZEACV.mjs";
|
|
77
78
|
import "./chunk-GN44PST5.mjs";
|
|
78
79
|
|
|
79
80
|
// src/server/adapters/factory.js
|
|
@@ -676,6 +677,7 @@ export {
|
|
|
676
677
|
decryptPayload,
|
|
677
678
|
deriveUserEncryptionKey,
|
|
678
679
|
encryptForStorage,
|
|
680
|
+
encryptPayload,
|
|
679
681
|
ensureSchema,
|
|
680
682
|
getSchemaVersion,
|
|
681
683
|
hasChatCredRef,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} AttachmentRef
|
|
3
|
+
* @property {1} version
|
|
4
|
+
* @property {string} namespace
|
|
5
|
+
* @property {string} key
|
|
6
|
+
* @property {string} taskUuid
|
|
7
|
+
* @property {number} occurrenceMs
|
|
8
|
+
* @property {number} expiresAt
|
|
9
|
+
*/
|
|
10
|
+
/** Each write gets an independent immutable identity. Reads never delete: an
|
|
11
|
+
* outbox retry or another device can still resolve the same reference. Shorter
|
|
12
|
+
* TTLs expire logically; cron defaults to 30-day physical retention, which the host may override.
|
|
13
|
+
* @param {{ task: Object, occurrenceMs: number|null, writeState: Function, now: () => number }} args
|
|
14
|
+
*/
|
|
15
|
+
export function createAttachmentStore({ task, occurrenceMs, writeState, now }: {
|
|
16
|
+
task: any;
|
|
17
|
+
occurrenceMs: number | null;
|
|
18
|
+
writeState: Function;
|
|
19
|
+
now: () => number;
|
|
20
|
+
}): (value: string, { ttlMs, owner, kind, ownerGeneration }?: {
|
|
21
|
+
ttlMs?: number;
|
|
22
|
+
owner?: {
|
|
23
|
+
type: string;
|
|
24
|
+
id: string;
|
|
25
|
+
};
|
|
26
|
+
kind?: string;
|
|
27
|
+
ownerGeneration?: number;
|
|
28
|
+
}) => Promise<AttachmentRef>;
|
|
29
|
+
export const ATTACHMENT_NAMESPACE: "amsg:attachments";
|
|
30
|
+
export const ATTACHMENT_RETENTION_DAYS: 30;
|
|
31
|
+
export const MAX_ATTACHMENT_TTL_MS: number;
|
|
32
|
+
export type AttachmentRef = {
|
|
33
|
+
version: 1;
|
|
34
|
+
namespace: string;
|
|
35
|
+
key: string;
|
|
36
|
+
taskUuid: string;
|
|
37
|
+
occurrenceMs: number;
|
|
38
|
+
expiresAt: number;
|
|
39
|
+
};
|
|
@@ -52,12 +52,13 @@ export function planClientStateCleanup(ttl: Record<string, number> | null | unde
|
|
|
52
52
|
* 比较用它(写进行的 updated_at 列);没带照旧用 `updatedAt`。
|
|
53
53
|
* @param {() => number} [args.now] - 取服务端当前时刻(测试可注入假时钟)。适配器
|
|
54
54
|
* 拿它认出库里「来自未来」的脏行。
|
|
55
|
-
* @returns {Promise<{ upserted: number, skipped: number, deleted: number, skippedEntries: Array<{ namespace: string, key: string }> }>}
|
|
56
|
-
* `upserted` / `skipped` / `deleted`
|
|
57
|
-
*
|
|
55
|
+
* @returns {Promise<{ upserted: number, skipped: number, deleted: number, unknown?: number, skippedEntries: Array<{ namespace: string, key: string }> }>}
|
|
56
|
+
* `upserted` / `skipped` / `deleted` 按逻辑条目计(切片行不计)。旧适配器
|
|
57
|
+
* 回执不完整时,未能确认的逻辑写入计入可选的 `unknown`。四者之和等于条目数。
|
|
58
|
+
* `deleted` 是删除之后 key 已不在库里的条数——删掉了、或本来就没有,
|
|
58
59
|
* 两种都算;被 last-write-wins 拦下的删除(库里那行更新)计入 `skipped`。
|
|
59
60
|
* `skippedEntries` 逐条列出被拦下的 key,写入与删除都在里面(适配器不回
|
|
60
|
-
* outcomes / cleanupOutcomes
|
|
61
|
+
* outcomes / cleanupOutcomes 时,仅整批物理行写入成功可折算成逻辑计数;其余写入计入 unknown,删除一律
|
|
61
62
|
* 按「已删」计)。
|
|
62
63
|
*/
|
|
63
64
|
export function writeClientStateEntries({ db, userId, userKey, entries, now }: {
|
|
@@ -78,6 +79,7 @@ export function writeClientStateEntries({ db, userId, userKey, entries, now }: {
|
|
|
78
79
|
upserted: number;
|
|
79
80
|
skipped: number;
|
|
80
81
|
deleted: number;
|
|
82
|
+
unknown?: number;
|
|
81
83
|
skippedEntries: Array<{
|
|
82
84
|
namespace: string;
|
|
83
85
|
key: string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {Object} StateAccessors
|
|
3
|
-
* @property {(namespace: string) => Promise<Array<{ namespace: string, key: string, value: string, updatedAt: number }>>} readState
|
|
4
|
-
* 一个 namespace
|
|
3
|
+
* @property {(namespace: string, options?: { key?: string }) => Promise<Array<{ namespace: string, key: string, value: string, updatedAt: number }>>} readState
|
|
4
|
+
* 一个 namespace 下的全部条目,或指定 key 的零至一条(值已解密、分块的已拼回原文)。适配器不支持
|
|
5
5
|
* client_state 时返回空数组——读不到状态,hook 走自己的兜底就行。
|
|
6
|
-
* @property {(namespace: string, entries: Array<{ key: string, value: string|null, updatedAt?: number }>) => Promise<{ upserted: number, skipped: number, deleted: number }>} writeState
|
|
6
|
+
* @property {(namespace: string, entries: Array<{ key: string, value: string|null, updatedAt?: number }>) => Promise<{ upserted: number, skipped: number, deleted: number, unknown?: number }>} writeState
|
|
7
7
|
* 批量写。`value` 是字符串 → 整条覆盖(不是追加,宿主自己序列化);
|
|
8
8
|
* `value` 为 `null` → 删掉这个 key(连它的分块切片行一起)。`updatedAt`
|
|
9
9
|
* 默认取当前时刻,语义与客户端同步一致:比库里已有值旧的写入(或删除)
|
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
* lib/webpush-webcrypto.js 的 MAX_PUSH_PAYLOAD_BYTES),塞不下的内容先写进
|
|
19
19
|
* client_state,push 里只带一个引用键,客户端上线后按键取回。
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* 谁清、什么时候清:普通命名空间默认不过期,宿主可用 clientStateTtl 配清理
|
|
22
|
+
* 天数;amsg:attachments 默认 30 天且宿主同名配置优先。普通旁路内容可以放在
|
|
23
|
+
* 固定的少量 key 上(例如每个角色一个),下次写同一个 key 直接覆盖,存量天然
|
|
24
|
+
* 有上限;一次性的大内容在确认客户端取走后,
|
|
24
25
|
* 用 `{ key, value: null }` 删掉。`DELETE /client-state` 仍然是清空这个用户
|
|
25
26
|
* 全部状态的兜底。
|
|
26
27
|
*
|
|
@@ -41,10 +42,12 @@ export function createStateAccessors({ db, userId, userKey, maxStateValueBytes,
|
|
|
41
42
|
}): StateAccessors;
|
|
42
43
|
export type StateAccessors = {
|
|
43
44
|
/**
|
|
44
|
-
* 一个 namespace
|
|
45
|
+
* 一个 namespace 下的全部条目,或指定 key 的零至一条(值已解密、分块的已拼回原文)。适配器不支持
|
|
45
46
|
* client_state 时返回空数组——读不到状态,hook 走自己的兜底就行。
|
|
46
47
|
*/
|
|
47
|
-
readState: (namespace: string
|
|
48
|
+
readState: (namespace: string, options?: {
|
|
49
|
+
key?: string;
|
|
50
|
+
}) => Promise<Array<{
|
|
48
51
|
namespace: string;
|
|
49
52
|
key: string;
|
|
50
53
|
value: string;
|
|
@@ -66,5 +69,6 @@ export type StateAccessors = {
|
|
|
66
69
|
upserted: number;
|
|
67
70
|
skipped: number;
|
|
68
71
|
deleted: number;
|
|
72
|
+
unknown?: number;
|
|
69
73
|
}>;
|
|
70
74
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 任务行的对外投影:`GET /messages` 列出来的那一份形状。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `ctx.scheduleTask()`
|
|
4
|
+
* HTTP 列表/单条接口与 fire-time hook 的任务查询、变更回执共用。
|
|
5
|
+
* `ctx.scheduleTask()` 创建和撞 uuid 时均带完整 metadata。各处基础字段
|
|
6
6
|
* 一样,宿主拿到哪一份都能直接进自己的任务面板。
|
|
7
7
|
*
|
|
8
8
|
* 白名单式取字段:解密后的 payload 里还躺着 `apiKey` / `apiUrl` /
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rei-standard/amsg-server",
|
|
3
|
-
"version": "3.0.0",
|
|
3
|
+
"version": "3.1.0-next.0",
|
|
4
4
|
"description": "ReiStandard Active Messaging server SDK with pluggable database adapters. Three-axis push schema (messageKind / messageType / messageSubtype) from @rei-standard/amsg-shared. Auto-emits ReasoningPush when the LLM response carries reasoning_content.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|