cmp-aws-database 2.1.2-dev.7 → 2.1.2-dev.70
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/config/table-names.d.ts +14 -0
- package/dist/config/table-names.js +15 -1
- package/dist/customer-user/accompaniments/accompaniments-model.d.ts +1 -0
- package/dist/customer-user/accompaniments/accompaniments-model.js +5 -1
- package/dist/customer-user/add-ons/add-ons-model.d.ts +3 -0
- package/dist/customer-user/add-ons/add-ons-model.js +13 -1
- package/dist/customer-user/browse-history/browse-history-dao.d.ts +122 -0
- package/dist/customer-user/browse-history/browse-history-dao.js +173 -0
- package/dist/customer-user/browse-history/browse-history-model.d.ts +31 -0
- package/dist/customer-user/browse-history/browse-history-model.js +118 -0
- package/dist/customer-user/cart/cart-categories-model.d.ts +6 -2
- package/dist/customer-user/cart/cart-categories-model.js +15 -3
- package/dist/customer-user/cart/cart-model.d.ts +14 -0
- package/dist/customer-user/cart/cart-model.js +48 -2
- package/dist/customer-user/category/category-dao.d.ts +29 -0
- package/dist/customer-user/category/category-dao.js +52 -1
- package/dist/customer-user/category/category-model.d.ts +1 -0
- package/dist/customer-user/category/category-model.js +5 -1
- package/dist/customer-user/cutlery/cutlery-model.d.ts +3 -0
- package/dist/customer-user/cutlery/cutlery-model.js +13 -1
- package/dist/customer-user/default-platter/default-platters-model.d.ts +2 -0
- package/dist/customer-user/default-platter/default-platters-model.js +9 -1
- package/dist/customer-user/default-platter/default_platters_items.d.ts +1 -0
- package/dist/customer-user/default-platter/default_platters_items.js +5 -1
- package/dist/customer-user/elphie/elphie-errors.d.ts +15 -0
- package/dist/customer-user/elphie/elphie-errors.js +31 -0
- package/dist/customer-user/elphie/elphie-message-dao.d.ts +51 -0
- package/dist/customer-user/elphie/elphie-message-dao.js +160 -0
- package/dist/customer-user/elphie/elphie-message-model.d.ts +25 -0
- package/dist/customer-user/elphie/elphie-message-model.js +78 -0
- package/dist/customer-user/elphie/elphie-session-dao.d.ts +46 -0
- package/dist/customer-user/elphie/elphie-session-dao.js +134 -0
- package/dist/customer-user/elphie/elphie-session-model.d.ts +26 -0
- package/dist/customer-user/elphie/elphie-session-model.js +55 -0
- package/dist/customer-user/fmpRequestCallback/fmp-request-callback-model.d.ts +1 -0
- package/dist/customer-user/fmpRequestCallback/fmp-request-callback-model.js +5 -1
- package/dist/customer-user/items/items-model.d.ts +2 -0
- package/dist/customer-user/items/items-model.js +9 -1
- package/dist/customer-user/items-bundle/items-bundle-dao.d.ts +72 -0
- package/dist/customer-user/items-bundle/items-bundle-dao.js +117 -0
- package/dist/customer-user/items-bundle/items-bundle-model.d.ts +23 -0
- package/dist/customer-user/items-bundle/items-bundle-model.js +62 -0
- package/dist/customer-user/lsq-priority-updation/lsq-priority-updation-dao.d.ts +140 -0
- package/dist/customer-user/lsq-priority-updation/lsq-priority-updation-dao.js +253 -0
- package/dist/customer-user/lsq-priority-updation/lsq-priority-updation-model.d.ts +63 -0
- package/dist/customer-user/lsq-priority-updation/lsq-priority-updation-model.js +135 -0
- package/dist/customer-user/order-module/order/order-model.d.ts +1 -0
- package/dist/customer-user/order-module/order/order-model.js +5 -1
- package/dist/customer-user/order-module/plate-order/plate-order-model.d.ts +20 -0
- package/dist/customer-user/order-module/plate-order/plate-order-model.js +69 -2
- package/dist/customer-user/order-module/tracking/tracking-model.d.ts +9 -0
- package/dist/customer-user/order-module/tracking/tracking-model.js +33 -2
- package/dist/customer-user/replace-items/replace-items-model.d.ts +1 -0
- package/dist/customer-user/replace-items/replace-items-model.js +5 -1
- package/dist/customer-user/resume-journey/resume-journey-model.d.ts +11 -0
- package/dist/customer-user/resume-journey/resume-journey-model.js +41 -2
- package/dist/customer-user/testing-session/testing-session-dao.d.ts +86 -0
- package/dist/customer-user/testing-session/testing-session-dao.js +149 -0
- package/dist/customer-user/testing-session/testing-session-model.d.ts +30 -0
- package/dist/customer-user/testing-session/testing-session-model.js +104 -0
- package/dist/patner-third-party/third-party-api-key/third-party-api-key-dao.d.ts +114 -0
- package/dist/patner-third-party/third-party-api-key/third-party-api-key-dao.js +225 -0
- package/dist/patner-third-party/third-party-api-key/third-party-api-key-model.d.ts +21 -0
- package/dist/patner-third-party/third-party-api-key/third-party-api-key-model.js +70 -0
- package/index.js +13 -1
- package/package.json +1 -1
|
@@ -46,6 +46,10 @@ __decorate([
|
|
|
46
46
|
(0, annotations_1.attribute)(),
|
|
47
47
|
__metadata("design:type", Number)
|
|
48
48
|
], DefaultPlattersItems.prototype, "itemQuantity", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, annotations_1.attribute)(),
|
|
51
|
+
__metadata("design:type", Number)
|
|
52
|
+
], DefaultPlattersItems.prototype, "itemMaxQuantity", void 0);
|
|
49
53
|
__decorate([
|
|
50
54
|
(0, annotations_1.attribute)(),
|
|
51
55
|
__metadata("design:type", String)
|
|
@@ -85,4 +89,4 @@ __decorate([
|
|
|
85
89
|
exports.DefaultPlattersItems = DefaultPlattersItems = __decorate([
|
|
86
90
|
(0, annotations_1.table)("DefaultPlatterItemsTable")
|
|
87
91
|
], DefaultPlattersItems);
|
|
88
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
92
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdF9wbGF0dGVyc19pdGVtcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jdXN0b21lci11c2VyL2RlZmF1bHQtcGxhdHRlci9kZWZhdWx0X3BsYXR0ZXJzX2l0ZW1zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLHVEQUE0RTtBQUM1RSxpREFBNkM7QUFHdEMsSUFBTSxvQkFBb0IsR0FBMUIsTUFBTSxvQkFBcUIsU0FBUSxzQkFBUztDQXVDbEQsQ0FBQTtBQXZDWSxvREFBb0I7QUFFN0I7SUFEQyxJQUFBLHFCQUFPLEVBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7O29EQUNiO0FBR2Y7SUFGQyxJQUFBLHNCQUFRLEVBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7SUFDNUIsSUFBQSx1QkFBUyxFQUFDLEVBQUUsc0JBQXNCLEVBQUUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDOzt1REFDaEU7QUFLbEI7SUFIQyxJQUFBLHVCQUFTLEVBQUM7UUFDUCxzQkFBc0IsRUFBRSxFQUFFLHNCQUFzQixFQUFFLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRO0tBQzlFLENBQUM7O3dEQUNpQjtBQUVuQjtJQURDLElBQUEsdUJBQVMsR0FBRTs7MERBQ1U7QUFFdEI7SUFEQyxJQUFBLHVCQUFTLEdBQUU7O3NEQUNNO0FBRWxCO0lBREMsSUFBQSx1QkFBUyxHQUFFOzsyREFDVztBQUV2QjtJQURDLElBQUEsdUJBQVMsR0FBRTs7MERBQ1U7QUFFdEI7SUFEQyxJQUFBLHVCQUFTLEdBQUU7OzZEQUNhO0FBRXpCO0lBREMsSUFBQSx1QkFBUyxHQUFFOzs4REFDYztBQUUxQjtJQURDLElBQUEsdUJBQVMsR0FBRTs7MERBQ1U7QUFFdEI7SUFEQyxJQUFBLHVCQUFTLEdBQUU7O3lEQUNTO0FBRXJCO0lBREMsSUFBQSx1QkFBUyxHQUFFOztxREFDSztBQUVqQjtJQURDLElBQUEsdUJBQVMsRUFBQyxFQUFFLHNCQUFzQixFQUFFLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDOzt3REFDakU7QUFFcEI7SUFEQyxJQUFBLHVCQUFTLEdBQUU7O3dEQUNVO0FBRXRCO0lBREMsSUFBQSx1QkFBUyxHQUFFOztxRUFDcUI7QUFFakM7SUFEQyxJQUFBLHVCQUFTLEdBQUU7O3dEQUNTO0FBRXJCO0lBREMsSUFBQSx1QkFBUyxHQUFFOztxRUFDcUI7K0JBdEN4QixvQkFBb0I7SUFEaEMsSUFBQSxtQkFBSyxFQUFDLDBCQUEwQixDQUFDO0dBQ3JCLG9CQUFvQixDQXVDaEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBhdHRyaWJ1dGUsIGhhc2hLZXksIHJhbmdlS2V5LCB0YWJsZSB9IGZyb20gXCJAbm92YS1vZG0vYW5ub3RhdGlvbnNcIjtcbmltcG9ydCB7IEJhc2VNb2RlbCB9IGZyb20gXCIuLi8uLi9iYXNlLW1vZGVsXCI7XG5cbkB0YWJsZShcIkRlZmF1bHRQbGF0dGVySXRlbXNUYWJsZVwiKVxuZXhwb3J0IGNsYXNzIERlZmF1bHRQbGF0dGVyc0l0ZW1zIGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgICBAaGFzaEtleSh7IHR5cGU6IFwiU3RyaW5nXCIgfSlcbiAgICBpdGVtSWQ6IHN0cmluZztcbiAgICBAcmFuZ2VLZXkoeyB0eXBlOiBcIlN0cmluZ1wiIH0pXG4gICAgQGF0dHJpYnV0ZSh7IGluZGV4S2V5Q29uZmlndXJhdGlvbnM6IHsgXCJwbGF0dGVySW5kZXhcIjogXCJIQVNIXCIgfSwgdHlwZTogJ1N0cmluZycgfSlcbiAgICBwbGF0dGVySWQ6IHN0cmluZztcblxuICAgIEBhdHRyaWJ1dGUoe1xuICAgICAgICBpbmRleEtleUNvbmZpZ3VyYXRpb25zOiB7IFwicGxhdHRlckNhdGVnb3J5SW5kZXhcIjogXCJSQU5HRVwiIH0sIHR5cGU6ICdTdHJpbmcnXG4gICAgfSlcbiAgICBjYXRlZ29yeUlkOiBzdHJpbmc7XG4gICAgQGF0dHJpYnV0ZSgpXG4gICAgY2F0ZWdvcnlOYW1lPzogc3RyaW5nO1xuICAgIEBhdHRyaWJ1dGUoKVxuICAgIGl0ZW1OYW1lPzogc3RyaW5nO1xuICAgIEBhdHRyaWJ1dGUoKVxuICAgIGl0ZW1CYXNlUHJpY2U/OiBudW1iZXI7XG4gICAgQGF0dHJpYnV0ZSgpXG4gICAgaXRlbVF1YW50aXR5PzogbnVtYmVyO1xuICAgIEBhdHRyaWJ1dGUoKVxuICAgIGl0ZW1NYXhRdWFudGl0eT86IG51bWJlcjtcbiAgICBAYXR0cmlidXRlKClcbiAgICBpdGVtUXVhbnRpdHlVbml0Pzogc3RyaW5nO1xuICAgIEBhdHRyaWJ1dGUoKVxuICAgIGl0ZW1NaW5QcmljZT86IG51bWJlcjtcbiAgICBAYXR0cmlidXRlKClcbiAgICBwbGF0dGVyTmFtZT86IHN0cmluZztcbiAgICBAYXR0cmlidXRlKClcbiAgICBwcmVtaXVtPzogc3RyaW5nO1xuICAgIEBhdHRyaWJ1dGUoeyBpbmRleEtleUNvbmZpZ3VyYXRpb25zOiB7IFwiaXRlbUFjdGl2ZUluZGV4XCI6IFwiSEFTSFwiIH0sIHR5cGU6ICdTdHJpbmcnIH0pXG4gICAgaXRlbUFjdGl2ZT86IHN0cmluZzsgLy8gVjJcbiAgICBAYXR0cmlidXRlKClcbiAgICBkYXlzT2ZXZWVrPzogc3RyaW5nW107XG4gICAgQGF0dHJpYnV0ZSgpXG4gICAgZnJlZUFjY29tcGFuaW1lbnRzTGltaXQ/OiBudW1iZXI7IC8vIEZvciBhY2NvbXBsaW1lbnRzVGFibGUgVmFsdWUgQ2hlY2tcbiAgICBAYXR0cmlidXRlKClcbiAgICBpc0Jhc2VJdGVtPzogYm9vbGVhbjsgLy8gRm9yIHBsYXR0ZXJJbWFnZSBWYWx1ZSBDaGVja1xuICAgIEBhdHRyaWJ1dGUoKVxuICAgIGl0ZW1EaXNjb3VudEZhY3RvclZhbHVlPzogbnVtYmVyOyAvLyBWMlxufSJdfQ==
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors for Elphie DynamoDB access — callers should not see raw Dynamoose/AWS errors.
|
|
3
|
+
*/
|
|
4
|
+
export declare class SessionNotFoundError extends Error {
|
|
5
|
+
readonly statusCode = 404;
|
|
6
|
+
constructor(elphieSessionId: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class ConversationNotFoundError extends Error {
|
|
9
|
+
readonly statusCode = 404;
|
|
10
|
+
constructor(conversationId: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class ElphieValidationError extends Error {
|
|
13
|
+
readonly statusCode = 400;
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Typed errors for Elphie DynamoDB access — callers should not see raw Dynamoose/AWS errors.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ElphieValidationError = exports.ConversationNotFoundError = exports.SessionNotFoundError = void 0;
|
|
7
|
+
class SessionNotFoundError extends Error {
|
|
8
|
+
constructor(elphieSessionId) {
|
|
9
|
+
super(`Elphie session not found: ${elphieSessionId}`);
|
|
10
|
+
this.statusCode = 404;
|
|
11
|
+
this.name = "SessionNotFoundError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.SessionNotFoundError = SessionNotFoundError;
|
|
15
|
+
class ConversationNotFoundError extends Error {
|
|
16
|
+
constructor(conversationId) {
|
|
17
|
+
super(`Elphie conversation not found: ${conversationId}`);
|
|
18
|
+
this.statusCode = 404;
|
|
19
|
+
this.name = "ConversationNotFoundError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.ConversationNotFoundError = ConversationNotFoundError;
|
|
23
|
+
class ElphieValidationError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.statusCode = 400;
|
|
27
|
+
this.name = "ElphieValidationError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.ElphieValidationError = ElphieValidationError;
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxwaGllLWVycm9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jdXN0b21lci11c2VyL2VscGhpZS9lbHBoaWUtZXJyb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7O0FBRUgsTUFBYSxvQkFBcUIsU0FBUSxLQUFLO0lBRzNDLFlBQVksZUFBdUI7UUFDL0IsS0FBSyxDQUFDLDZCQUE2QixlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBSGpELGVBQVUsR0FBRyxHQUFHLENBQUM7UUFJdEIsSUFBSSxDQUFDLElBQUksR0FBRyxzQkFBc0IsQ0FBQztJQUN2QyxDQUFDO0NBQ0o7QUFQRCxvREFPQztBQUVELE1BQWEseUJBQTBCLFNBQVEsS0FBSztJQUdoRCxZQUFZLGNBQXNCO1FBQzlCLEtBQUssQ0FBQyxrQ0FBa0MsY0FBYyxFQUFFLENBQUMsQ0FBQztRQUhyRCxlQUFVLEdBQUcsR0FBRyxDQUFDO1FBSXRCLElBQUksQ0FBQyxJQUFJLEdBQUcsMkJBQTJCLENBQUM7SUFDNUMsQ0FBQztDQUNKO0FBUEQsOERBT0M7QUFFRCxNQUFhLHFCQUFzQixTQUFRLEtBQUs7SUFHNUMsWUFBWSxPQUFlO1FBQ3ZCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUhWLGVBQVUsR0FBRyxHQUFHLENBQUM7UUFJdEIsSUFBSSxDQUFDLElBQUksR0FBRyx1QkFBdUIsQ0FBQztJQUN4QyxDQUFDO0NBQ0o7QUFQRCxzREFPQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVHlwZWQgZXJyb3JzIGZvciBFbHBoaWUgRHluYW1vREIgYWNjZXNzIOKAlCBjYWxsZXJzIHNob3VsZCBub3Qgc2VlIHJhdyBEeW5hbW9vc2UvQVdTIGVycm9ycy5cbiAqL1xuXG5leHBvcnQgY2xhc3MgU2Vzc2lvbk5vdEZvdW5kRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gICAgcmVhZG9ubHkgc3RhdHVzQ29kZSA9IDQwNDtcblxuICAgIGNvbnN0cnVjdG9yKGVscGhpZVNlc3Npb25JZDogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKGBFbHBoaWUgc2Vzc2lvbiBub3QgZm91bmQ6ICR7ZWxwaGllU2Vzc2lvbklkfWApO1xuICAgICAgICB0aGlzLm5hbWUgPSBcIlNlc3Npb25Ob3RGb3VuZEVycm9yXCI7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgQ29udmVyc2F0aW9uTm90Rm91bmRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgICByZWFkb25seSBzdGF0dXNDb2RlID0gNDA0O1xuXG4gICAgY29uc3RydWN0b3IoY29udmVyc2F0aW9uSWQ6IHN0cmluZykge1xuICAgICAgICBzdXBlcihgRWxwaGllIGNvbnZlcnNhdGlvbiBub3QgZm91bmQ6ICR7Y29udmVyc2F0aW9uSWR9YCk7XG4gICAgICAgIHRoaXMubmFtZSA9IFwiQ29udmVyc2F0aW9uTm90Rm91bmRFcnJvclwiO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVscGhpZVZhbGlkYXRpb25FcnJvciBleHRlbmRzIEVycm9yIHtcbiAgICByZWFkb25seSBzdGF0dXNDb2RlID0gNDAwO1xuXG4gICAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgICAgICB0aGlzLm5hbWUgPSBcIkVscGhpZVZhbGlkYXRpb25FcnJvclwiO1xuICAgIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DynamoKey } from "../../base-dynamoose-dao";
|
|
2
|
+
import { CreateElphieConversationInput, ElphieMessage, ElphieMessageTurn } from "./elphie-message-model";
|
|
3
|
+
type ListResult = {
|
|
4
|
+
items: ElphieMessage[];
|
|
5
|
+
lastKey?: DynamoKey;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Service/DAO for `elphie_messages`.
|
|
9
|
+
*
|
|
10
|
+
* HASH: `conversation_id`.
|
|
11
|
+
* Turn append uses Dynamoose `$APPEND` (atomic) — never full-item read-modify-write.
|
|
12
|
+
*/
|
|
13
|
+
declare class ElphieMessageService {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a conversation with the first turn already in `content`.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* await elphieMessageService.createConversation({
|
|
19
|
+
* conversation_id: "conv-1",
|
|
20
|
+
* user_id: "user-1",
|
|
21
|
+
* elphieSessionId: "session-uuid",
|
|
22
|
+
* firstTurn: { role: "user", text: "Hi", timestamp: new Date().toISOString() }
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
createConversation: (input: CreateElphieConversationInput) => Promise<ElphieMessage>;
|
|
26
|
+
/**
|
|
27
|
+
* Atomically appends one turn to `content` and refreshes `updated_at`.
|
|
28
|
+
* Uses `$APPEND` so concurrent turns cannot lose updates.
|
|
29
|
+
*/
|
|
30
|
+
appendTurn: (conversation_id: string, turn: ElphieMessageTurn) => Promise<ElphieMessage>;
|
|
31
|
+
/**
|
|
32
|
+
* Fetches one conversation by `conversation_id`.
|
|
33
|
+
* Throws `ConversationNotFoundError` when missing.
|
|
34
|
+
*/
|
|
35
|
+
getConversation: (conversation_id: string) => Promise<ElphieMessage>;
|
|
36
|
+
/**
|
|
37
|
+
* Lists conversations for a user via GSI `user_id-index`.
|
|
38
|
+
* Newest-first order is applied in memory on `updated_at` (not a GSI range key).
|
|
39
|
+
*/
|
|
40
|
+
listConversationsForUser: (user_id: string, { limit, lastKey }?: {
|
|
41
|
+
limit?: number;
|
|
42
|
+
lastKey?: DynamoKey;
|
|
43
|
+
}) => Promise<ListResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Lists conversations linked to a session via GSI `elphieSessionId-index`.
|
|
46
|
+
*/
|
|
47
|
+
listConversationsForSession: (elphieSessionId: string) => Promise<ElphieMessage[]>;
|
|
48
|
+
private assertValidTurn;
|
|
49
|
+
}
|
|
50
|
+
export declare const elphieMessageService: ElphieMessageService;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.elphieMessageService = void 0;
|
|
7
|
+
const dynamoose_1 = __importDefault(require("dynamoose"));
|
|
8
|
+
const elphie_errors_1 = require("./elphie-errors");
|
|
9
|
+
const elphie_message_model_1 = require("./elphie-message-model");
|
|
10
|
+
const nowIso = () => new Date().toISOString();
|
|
11
|
+
const isValidRole = (role) => role === elphie_message_model_1.ELPHIE_MESSAGE_ROLE.USER || role === elphie_message_model_1.ELPHIE_MESSAGE_ROLE.ELPHIE;
|
|
12
|
+
/**
|
|
13
|
+
* Service/DAO for `elphie_messages`.
|
|
14
|
+
*
|
|
15
|
+
* HASH: `conversation_id`.
|
|
16
|
+
* Turn append uses Dynamoose `$APPEND` (atomic) — never full-item read-modify-write.
|
|
17
|
+
*/
|
|
18
|
+
class ElphieMessageService {
|
|
19
|
+
constructor() {
|
|
20
|
+
/**
|
|
21
|
+
* Creates a conversation with the first turn already in `content`.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* await elphieMessageService.createConversation({
|
|
25
|
+
* conversation_id: "conv-1",
|
|
26
|
+
* user_id: "user-1",
|
|
27
|
+
* elphieSessionId: "session-uuid",
|
|
28
|
+
* firstTurn: { role: "user", text: "Hi", timestamp: new Date().toISOString() }
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
this.createConversation = async (input) => {
|
|
32
|
+
this.assertValidTurn(input.firstTurn);
|
|
33
|
+
try {
|
|
34
|
+
const created = await elphie_message_model_1.ElphieMessageModel.create({
|
|
35
|
+
conversation_id: input.conversation_id,
|
|
36
|
+
user_id: input.user_id,
|
|
37
|
+
elphieSessionId: input.elphieSessionId,
|
|
38
|
+
content: [input.firstTurn],
|
|
39
|
+
updated_at: nowIso()
|
|
40
|
+
});
|
|
41
|
+
return created;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw wrapUnexpected("createConversation", error);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Atomically appends one turn to `content` and refreshes `updated_at`.
|
|
49
|
+
* Uses `$APPEND` so concurrent turns cannot lose updates.
|
|
50
|
+
*/
|
|
51
|
+
this.appendTurn = async (conversation_id, turn) => {
|
|
52
|
+
this.assertValidTurn(turn);
|
|
53
|
+
try {
|
|
54
|
+
// Dynamoose list append operator — not expressible as Partial<ElphieMessage>.
|
|
55
|
+
const updateObj = {
|
|
56
|
+
content: { $APPEND: [turn] },
|
|
57
|
+
updated_at: nowIso()
|
|
58
|
+
};
|
|
59
|
+
const updated = await elphie_message_model_1.ElphieMessageModel.update({ conversation_id }, updateObj, {
|
|
60
|
+
condition: new dynamoose_1.default.Condition().attribute("conversation_id").exists()
|
|
61
|
+
});
|
|
62
|
+
return updated;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (isNotFoundError(error) || isConditionalCheckFailed(error)) {
|
|
66
|
+
throw new elphie_errors_1.ConversationNotFoundError(conversation_id);
|
|
67
|
+
}
|
|
68
|
+
throw wrapUnexpected("appendTurn", error);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Fetches one conversation by `conversation_id`.
|
|
73
|
+
* Throws `ConversationNotFoundError` when missing.
|
|
74
|
+
*/
|
|
75
|
+
this.getConversation = async (conversation_id) => {
|
|
76
|
+
try {
|
|
77
|
+
const conversation = await elphie_message_model_1.ElphieMessageModel.get(conversation_id);
|
|
78
|
+
if (!conversation) {
|
|
79
|
+
throw new elphie_errors_1.ConversationNotFoundError(conversation_id);
|
|
80
|
+
}
|
|
81
|
+
return conversation;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof elphie_errors_1.ConversationNotFoundError) {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
if (isNotFoundError(error)) {
|
|
88
|
+
throw new elphie_errors_1.ConversationNotFoundError(conversation_id);
|
|
89
|
+
}
|
|
90
|
+
throw wrapUnexpected("getConversation", error);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Lists conversations for a user via GSI `user_id-index`.
|
|
95
|
+
* Newest-first order is applied in memory on `updated_at` (not a GSI range key).
|
|
96
|
+
*/
|
|
97
|
+
this.listConversationsForUser = async (user_id, { limit, lastKey } = {}) => {
|
|
98
|
+
try {
|
|
99
|
+
let queryBuilder = elphie_message_model_1.ElphieMessageModel.query("user_id")
|
|
100
|
+
.eq(user_id)
|
|
101
|
+
.using("user_id-index");
|
|
102
|
+
if (lastKey) {
|
|
103
|
+
queryBuilder = queryBuilder.startAt(lastKey);
|
|
104
|
+
}
|
|
105
|
+
if (typeof limit === "number") {
|
|
106
|
+
queryBuilder = queryBuilder.limit(limit);
|
|
107
|
+
}
|
|
108
|
+
const queryResult = await queryBuilder.exec();
|
|
109
|
+
const items = [...queryResult].sort((a, b) => (b.updated_at ?? "").localeCompare(a.updated_at ?? ""));
|
|
110
|
+
return {
|
|
111
|
+
items,
|
|
112
|
+
lastKey: queryResult.lastKey
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw wrapUnexpected("listConversationsForUser", error);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Lists conversations linked to a session via GSI `elphieSessionId-index`.
|
|
121
|
+
*/
|
|
122
|
+
this.listConversationsForSession = async (elphieSessionId) => {
|
|
123
|
+
try {
|
|
124
|
+
const queryResult = await elphie_message_model_1.ElphieMessageModel.query("elphieSessionId")
|
|
125
|
+
.eq(elphieSessionId)
|
|
126
|
+
.using("elphieSessionId-index")
|
|
127
|
+
.exec();
|
|
128
|
+
return queryResult;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw wrapUnexpected("listConversationsForSession", error);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
this.assertValidTurn = (turn) => {
|
|
135
|
+
if (!turn || typeof turn.text !== "string" || turn.text.length === 0) {
|
|
136
|
+
throw new elphie_errors_1.ElphieValidationError("turn.text is required");
|
|
137
|
+
}
|
|
138
|
+
if (!isValidRole(turn.role)) {
|
|
139
|
+
throw new elphie_errors_1.ElphieValidationError(`Invalid turn.role "${turn.role}". Expected "user" | "elphie".`);
|
|
140
|
+
}
|
|
141
|
+
if (!turn.timestamp) {
|
|
142
|
+
throw new elphie_errors_1.ElphieValidationError("turn.timestamp is required");
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const isNotFoundError = (error) => {
|
|
148
|
+
const name = error?.name;
|
|
149
|
+
return name === "ItemNotFoundException" || name === "ItemNotFoundError";
|
|
150
|
+
};
|
|
151
|
+
const isConditionalCheckFailed = (error) => {
|
|
152
|
+
const name = error?.name;
|
|
153
|
+
return name === "ConditionalCheckFailedException";
|
|
154
|
+
};
|
|
155
|
+
const wrapUnexpected = (operation, error) => {
|
|
156
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
157
|
+
return new Error(`ElphieMessageService.${operation} failed: ${message}`);
|
|
158
|
+
};
|
|
159
|
+
exports.elphieMessageService = new ElphieMessageService();
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxwaGllLW1lc3NhZ2UtZGFvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2N1c3RvbWVyLXVzZXIvZWxwaGllL2VscGhpZS1tZXNzYWdlLWRhby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwwREFBa0M7QUFFbEMsbURBQW1GO0FBQ25GLGlFQU9nQztBQU9oQyxNQUFNLE1BQU0sR0FBRyxHQUFXLEVBQUUsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBRXRELE1BQU0sV0FBVyxHQUFHLENBQUMsSUFBWSxFQUE2QixFQUFFLENBQzVELElBQUksS0FBSywwQ0FBbUIsQ0FBQyxJQUFJLElBQUksSUFBSSxLQUFLLDBDQUFtQixDQUFDLE1BQU0sQ0FBQztBQUU3RTs7Ozs7R0FLRztBQUNILE1BQU0sb0JBQW9CO0lBQTFCO1FBQ0k7Ozs7Ozs7Ozs7V0FVRztRQUNILHVCQUFrQixHQUFHLEtBQUssRUFBRSxLQUFvQyxFQUEwQixFQUFFO1lBQ3hGLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRXRDLElBQUksQ0FBQztnQkFDRCxNQUFNLE9BQU8sR0FBRyxNQUFNLHlDQUFrQixDQUFDLE1BQU0sQ0FBQztvQkFDNUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxlQUFlO29CQUN0QyxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87b0JBQ3RCLGVBQWUsRUFBRSxLQUFLLENBQUMsZUFBZTtvQkFDdEMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztvQkFDMUIsVUFBVSxFQUFFLE1BQU0sRUFBRTtpQkFDdkIsQ0FBQyxDQUFDO2dCQUNILE9BQU8sT0FBd0IsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDYixNQUFNLGNBQWMsQ0FBQyxvQkFBb0IsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN0RCxDQUFDO1FBQ0ws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bEUsQ0FBQztZQUNOLENBQUM7WUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNsQixNQUFNLElBQUkscUNBQXFCLENBQUMsNEJBQTRCLENBQUMsQ0FBQztZQUNsRSxDQUFDO1FBQ0wsQ0FBQyxDQUFDO0lBQ04sQ0FBQztDQUFBO0FBRUQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxLQUFjLEVBQVcsRUFBRTtJQUNoRCxNQUFNLElBQUksR0FBSSxLQUFrQyxFQUFFLElBQUksQ0FBQztJQUN2RCxPQUFPLElBQUksS0FBSyx1QkFBdUIsSUFBSSxJQUFJLEtBQUssbUJBQW1CLENBQUM7QUFDNUUsQ0FBQyxDQUFDO0FBRUYsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLEtBQWMsRUFBVyxFQUFFO0lBQ3pELE1BQU0sSUFBSSxHQUFJLEtBQWtDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZELE9BQU8sSUFBSSxLQUFLLGlDQUFpQyxDQUFDO0FBQ3RELENBQUMsQ0FBQztBQUVGLE1BQU0sY0FBYyxHQUFHLENBQUMsU0FBaUIsRUFBRSxLQUFjLEVBQVMsRUFBRTtJQUNoRSxNQUFNLE9BQU8sR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkUsT0FBTyxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsU0FBUyxZQUFZLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDN0UsQ0FBQyxDQUFDO0FBRVcsUUFBQSxvQkFBb0IsR0FBRyxJQUFJLG9CQUFvQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZHluYW1vb3NlIGZyb20gXCJkeW5hbW9vc2VcIjtcbmltcG9ydCB7IER5bmFtb0tleSB9IGZyb20gXCIuLi8uLi9iYXNlLWR5bmFtb29zZS1kYW9cIjtcbmltcG9ydCB7IENvbnZlcnNhdGlvbk5vdEZvdW5kRXJyb3IsIEVscGhpZVZhbGlkYXRpb25FcnJvciB9IGZyb20gXCIuL2VscGhpZS1lcnJvcnNcIjtcbmltcG9ydCB7XG4gICAgQ3JlYXRlRWxwaGllQ29udmVyc2F0aW9uSW5wdXQsXG4gICAgRUxQSElFX01FU1NBR0VfUk9MRSxcbiAgICBFbHBoaWVNZXNzYWdlLFxuICAgIEVscGhpZU1lc3NhZ2VNb2RlbCxcbiAgICBFbHBoaWVNZXNzYWdlUm9sZSxcbiAgICBFbHBoaWVNZXNzYWdlVHVyblxufSBmcm9tIFwiLi9lbHBoaWUtbWVzc2FnZS1tb2RlbFwiO1xuXG50eXBlIExpc3RSZXN1bHQgPSB7XG4gICAgaXRlbXM6IEVscGhpZU1lc3NhZ2VbXTtcbiAgICBsYXN0S2V5PzogRHluYW1vS2V5O1xufTtcblxuY29uc3Qgbm93SXNvID0gKCk6IHN0cmluZyA9PiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cbmNvbnN0IGlzVmFsaWRSb2xlID0gKHJvbGU6IHN0cmluZyk6IHJvbGUgaXMgRWxwaGllTWVzc2FnZVJvbGUgPT5cbiAgICByb2xlID09PSBFTFBISUVfTUVTU0FHRV9ST0xFLlVTRVIgfHwgcm9sZSA9PT0gRUxQSElFX01FU1NBR0VfUk9MRS5FTFBISUU7XG5cbi8qKlxuICogU2VydmljZS9EQU8gZm9yIGBlbHBoaWVfbWVzc2FnZXNgLlxuICpcbiAqIEhBU0g6IGBjb252ZXJzYXRpb25faWRgLlxuICogVHVybiBhcHBlbmQgdXNlcyBEeW5hbW9vc2UgYCRBUFBFTkRgIChhdG9taWMpIOKAlCBuZXZlciBmdWxsLWl0ZW0gcmVhZC1tb2RpZnktd3JpdGUuXG4gKi9cbmNsYXNzIEVscGhpZU1lc3NhZ2VTZXJ2aWNlIHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgY29udmVyc2F0aW9uIHdpdGggdGhlIGZpcnN0IHR1cm4gYWxyZWFkeSBpbiBgY29udGVudGAuXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGF3YWl0IGVscGhpZU1lc3NhZ2VTZXJ2aWNlLmNyZWF0ZUNvbnZlcnNhdGlvbih7XG4gICAgICogICAgIGNvbnZlcnNhdGlvbl9pZDogXCJjb252LTFcIixcbiAgICAgKiAgICAgdXNlcl9pZDogXCJ1c2VyLTFcIixcbiAgICAgKiAgICAgZWxwaGllU2Vzc2lvbklkOiBcInNlc3Npb24tdXVpZFwiLFxuICAgICAqICAgICBmaXJzdFR1cm46IHsgcm9sZTogXCJ1c2VyXCIsIHRleHQ6IFwiSGlcIiwgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkgfVxuICAgICAqIH0pO1xuICAgICAqL1xuICAgIGNyZWF0ZUNvbnZlcnNhdGlvbiA9IGFzeW5jIChpbnB1dDogQ3JlYXRlRWxwaGllQ29udmVyc2F0aW9uSW5wdXQpOiBQcm9taXNlPEVscGhpZU1lc3NhZ2U+ID0+IHtcbiAgICAgICAgdGhpcy5hc3NlcnRWYWxpZFR1cm4oaW5wdXQuZmlyc3RUdXJuKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IEVscGhpZU1lc3NhZ2VNb2RlbC5jcmVhdGUoe1xuICAgICAgICAgICAgICAgIGNvbnZlcnNhdGlvbl9pZDogaW5wdXQuY29udmVyc2F0aW9uX2lkLFxuICAgICAgICAgICAgICAgIHVzZXJfaWQ6IGlucHV0LnVzZXJfaWQsXG4gICAgICAgICAgICAgICAgZWxwaGllU2Vzc2lvbklkOiBpbnB1dC5lbHBoaWVTZXNzaW9uSWQsXG4gICAgICAgICAgICAgICAgY29udGVudDogW2lucHV0LmZpcnN0VHVybl0sXG4gICAgICAgICAgICAgICAgdXBkYXRlZF9hdDogbm93SXNvKClcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZWQgYXMgRWxwaGllTWVzc2FnZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRocm93IHdyYXBVbmV4cGVjdGVkKFwiY3JlYXRlQ29udmVyc2F0aW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBdG9taWNhbGx5IGFwcGVuZHMgb25lIHR1cm4gdG8gYGNvbnRlbnRgIGFuZCByZWZyZXNoZXMgYHVwZGF0ZWRfYXRgLlxuICAgICAqIFVzZXMgYCRBUFBFTkRgIHNvIGNvbmN1cnJlbnQgdHVybnMgY2Fubm90IGxvc2UgdXBkYXRlcy5cbiAgICAgKi9cbiAgICBhcHBlbmRUdXJuID0gYXN5bmMgKGNvbnZlcnNhdGlvbl9pZDogc3RyaW5nLCB0dXJuOiBFbHBoaWVNZXNzYWdlVHVybik6IFByb21pc2U8RWxwaGllTWVzc2FnZT4gPT4ge1xuICAgICAgICB0aGlzLmFzc2VydFZhbGlkVHVybih0dXJuKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gRHluYW1vb3NlIGxpc3QgYXBwZW5kIG9wZXJhdG9yIOKAlCBub3QgZXhwcmVzc2libGUgYXMgUGFydGlhbDxFbHBoaWVNZXNzYWdlPi5cbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZU9iaiA9IHtcbiAgICAgICAgICAgICAgICBjb250ZW50OiB7ICRBUFBFTkQ6IFt0dXJuXSB9LFxuICAgICAgICAgICAgICAgIHVwZGF0ZWRfYXQ6IG5vd0lzbygpXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlZCA9IGF3YWl0IEVscGhpZU1lc3NhZ2VNb2RlbC51cGRhdGUoXG4gICAgICAgICAgICAgICAgeyBjb252ZXJzYXRpb25faWQgfSxcbiAgICAgICAgICAgICAgICB1cGRhdGVPYmogYXMgdW5rbm93biBhcyBQYXJhbWV0ZXJzPHR5cGVvZiBFbHBoaWVNZXNzYWdlTW9kZWwudXBkYXRlPlsxXSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbjogbmV3IGR5bmFtb29zZS5Db25kaXRpb24oKS5hdHRyaWJ1dGUoXCJjb252ZXJzYXRpb25faWRcIikuZXhpc3RzKClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHVwZGF0ZWQgYXMgdW5rbm93biBhcyBFbHBoaWVNZXNzYWdlO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgaWYgKGlzTm90Rm91bmRFcnJvcihlcnJvcikgfHwgaXNDb25kaXRpb25hbENoZWNrRmFpbGVkKGVycm9yKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBDb252ZXJzYXRpb25Ob3RGb3VuZEVycm9yKGNvbnZlcnNhdGlvbl9pZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyB3cmFwVW5leHBlY3RlZChcImFwcGVuZFR1cm5cIiwgZXJyb3IpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZldGNoZXMgb25lIGNvbnZlcnNhdGlvbiBieSBgY29udmVyc2F0aW9uX2lkYC5cbiAgICAgKiBUaHJvd3MgYENvbnZlcnNhdGlvbk5vdEZvdW5kRXJyb3JgIHdoZW4gbWlzc2luZy5cbiAgICAgKi9cbiAgICBnZXRDb252ZXJzYXRpb24gPSBhc3luYyAoY29udmVyc2F0aW9uX2lkOiBzdHJpbmcpOiBQcm9taXNlPEVscGhpZU1lc3NhZ2U+ID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnZlcnNhdGlvbiA9IGF3YWl0IEVscGhpZU1lc3NhZ2VNb2RlbC5nZXQoY29udmVyc2F0aW9uX2lkKTtcbiAgICAgICAgICAgIGlmICghY29udmVyc2F0aW9uKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IENvbnZlcnNhdGlvbk5vdEZvdW5kRXJyb3IoY29udmVyc2F0aW9uX2lkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBjb252ZXJzYXRpb24gYXMgRWxwaGllTWVzc2FnZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIENvbnZlcnNhdGlvbk5vdEZvdW5kRXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChpc05vdEZvdW5kRXJyb3IoZXJyb3IpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IENvbnZlcnNhdGlvbk5vdEZvdW5kRXJyb3IoY29udmVyc2F0aW9uX2lkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IHdyYXBVbmV4cGVjdGVkKFwiZ2V0Q29udmVyc2F0aW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBMaXN0cyBjb252ZXJzYXRpb25zIGZvciBhIHVzZXIgdmlhIEdTSSBgdXNlcl9pZC1pbmRleGAuXG4gICAgICogTmV3ZXN0LWZpcnN0IG9yZGVyIGlzIGFwcGxpZWQgaW4gbWVtb3J5IG9uIGB1cGRhdGVkX2F0YCAobm90IGEgR1NJIHJhbmdlIGtleSkuXG4gICAgICovXG4gICAgbGlzdENvbnZlcnNhdGlvbnNGb3JVc2VyID0gYXN5bmMgKFxuICAgICAgICB1c2VyX2lkOiBzdHJpbmcsXG4gICAgICAgIHsgbGltaXQsIGxhc3RLZXkgfTogeyBsaW1pdD86IG51bWJlcjsgbGFzdEtleT86IER5bmFtb0tleSB9ID0ge31cbiAgICApOiBQcm9taXNlPExpc3RSZXN1bHQ+ID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBxdWVyeUJ1aWxkZXIgPSBFbHBoaWVNZXNzYWdlTW9kZWwucXVlcnkoXCJ1c2VyX2lkXCIpXG4gICAgICAgICAgICAgICAgLmVxKHVzZXJfaWQpXG4gICAgICAgICAgICAgICAgLnVzaW5nKFwidXNlcl9pZC1pbmRleFwiKTtcblxuICAgICAgICAgICAgaWYgKGxhc3RLZXkpIHtcbiAgICAgICAgICAgICAgICBxdWVyeUJ1aWxkZXIgPSBxdWVyeUJ1aWxkZXIuc3RhcnRBdChsYXN0S2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgbGltaXQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICBxdWVyeUJ1aWxkZXIgPSBxdWVyeUJ1aWxkZXIubGltaXQobGltaXQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBxdWVyeVJlc3VsdCA9IGF3YWl0IHF1ZXJ5QnVpbGRlci5leGVjKCk7XG4gICAgICAgICAgICBjb25zdCBpdGVtcyA9IFsuLi4ocXVlcnlSZXN1bHQgYXMgdW5rbm93biBhcyBFbHBoaWVNZXNzYWdlW10pXS5zb3J0KChhLCBiKSA9PlxuICAgICAgICAgICAgICAgIChiLnVwZGF0ZWRfYXQgPz8gXCJcIikubG9jYWxlQ29tcGFyZShhLnVwZGF0ZWRfYXQgPz8gXCJcIilcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGl0ZW1zLFxuICAgICAgICAgICAgICAgIGxhc3RLZXk6IHF1ZXJ5UmVzdWx0Lmxhc3RLZXkgYXMgRHluYW1vS2V5IHwgdW5kZWZpbmVkXG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhyb3cgd3JhcFVuZXhwZWN0ZWQoXCJsaXN0Q29udmVyc2F0aW9uc0ZvclVzZXJcIiwgZXJyb3IpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIExpc3RzIGNvbnZlcnNhdGlvbnMgbGlua2VkIHRvIGEgc2Vzc2lvbiB2aWEgR1NJIGBlbHBoaWVTZXNzaW9uSWQtaW5kZXhgLlxuICAgICAqL1xuICAgIGxpc3RDb252ZXJzYXRpb25zRm9yU2Vzc2lvbiA9IGFzeW5jIChlbHBoaWVTZXNzaW9uSWQ6IHN0cmluZyk6IFByb21pc2U8RWxwaGllTWVzc2FnZVtdPiA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBxdWVyeVJlc3VsdCA9IGF3YWl0IEVscGhpZU1lc3NhZ2VNb2RlbC5xdWVyeShcImVscGhpZVNlc3Npb25JZFwiKVxuICAgICAgICAgICAgICAgIC5lcShlbHBoaWVTZXNzaW9uSWQpXG4gICAgICAgICAgICAgICAgLnVzaW5nKFwiZWxwaGllU2Vzc2lvbklkLWluZGV4XCIpXG4gICAgICAgICAgICAgICAgLmV4ZWMoKTtcbiAgICAgICAgICAgIHJldHVybiBxdWVyeVJlc3VsdCBhcyB1bmtub3duIGFzIEVscGhpZU1lc3NhZ2VbXTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRocm93IHdyYXBVbmV4cGVjdGVkKFwibGlzdENvbnZlcnNhdGlvbnNGb3JTZXNzaW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIGFzc2VydFZhbGlkVHVybiA9ICh0dXJuOiBFbHBoaWVNZXNzYWdlVHVybik6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoIXR1cm4gfHwgdHlwZW9mIHR1cm4udGV4dCAhPT0gXCJzdHJpbmdcIiB8fCB0dXJuLnRleHQubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRWxwaGllVmFsaWRhdGlvbkVycm9yKFwidHVybi50ZXh0IGlzIHJlcXVpcmVkXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNWYWxpZFJvbGUodHVybi5yb2xlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVscGhpZVZhbGlkYXRpb25FcnJvcihcbiAgICAgICAgICAgICAgICBgSW52YWxpZCB0dXJuLnJvbGUgXCIke3R1cm4ucm9sZX1cIi4gRXhwZWN0ZWQgXCJ1c2VyXCIgfCBcImVscGhpZVwiLmBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0dXJuLnRpbWVzdGFtcCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVscGhpZVZhbGlkYXRpb25FcnJvcihcInR1cm4udGltZXN0YW1wIGlzIHJlcXVpcmVkXCIpO1xuICAgICAgICB9XG4gICAgfTtcbn1cblxuY29uc3QgaXNOb3RGb3VuZEVycm9yID0gKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiA9PiB7XG4gICAgY29uc3QgbmFtZSA9IChlcnJvciBhcyB7IG5hbWU/OiBzdHJpbmcgfSB8IG51bGwpPy5uYW1lO1xuICAgIHJldHVybiBuYW1lID09PSBcIkl0ZW1Ob3RGb3VuZEV4Y2VwdGlvblwiIHx8IG5hbWUgPT09IFwiSXRlbU5vdEZvdW5kRXJyb3JcIjtcbn07XG5cbmNvbnN0IGlzQ29uZGl0aW9uYWxDaGVja0ZhaWxlZCA9IChlcnJvcjogdW5rbm93bik6IGJvb2xlYW4gPT4ge1xuICAgIGNvbnN0IG5hbWUgPSAoZXJyb3IgYXMgeyBuYW1lPzogc3RyaW5nIH0gfCBudWxsKT8ubmFtZTtcbiAgICByZXR1cm4gbmFtZSA9PT0gXCJDb25kaXRpb25hbENoZWNrRmFpbGVkRXhjZXB0aW9uXCI7XG59O1xuXG5jb25zdCB3cmFwVW5leHBlY3RlZCA9IChvcGVyYXRpb246IHN0cmluZywgZXJyb3I6IHVua25vd24pOiBFcnJvciA9PiB7XG4gICAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbiAgICByZXR1cm4gbmV3IEVycm9yKGBFbHBoaWVNZXNzYWdlU2VydmljZS4ke29wZXJhdGlvbn0gZmFpbGVkOiAke21lc3NhZ2V9YCk7XG59O1xuXG5leHBvcnQgY29uc3QgZWxwaGllTWVzc2FnZVNlcnZpY2UgPSBuZXcgRWxwaGllTWVzc2FnZVNlcnZpY2UoKTtcbiJdfQ==
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Item } from "dynamoose/dist/Item";
|
|
2
|
+
export declare const ELPHIE_MESSAGE_ROLE: {
|
|
3
|
+
readonly USER: "user";
|
|
4
|
+
readonly ELPHIE: "elphie";
|
|
5
|
+
};
|
|
6
|
+
export type ElphieMessageRole = (typeof ELPHIE_MESSAGE_ROLE)[keyof typeof ELPHIE_MESSAGE_ROLE];
|
|
7
|
+
export interface ElphieMessageTurn {
|
|
8
|
+
role: ElphieMessageRole;
|
|
9
|
+
text: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ElphieMessage extends Item {
|
|
13
|
+
conversation_id: string;
|
|
14
|
+
user_id: string;
|
|
15
|
+
elphieSessionId: string;
|
|
16
|
+
content: ElphieMessageTurn[];
|
|
17
|
+
updated_at: string;
|
|
18
|
+
}
|
|
19
|
+
export type CreateElphieConversationInput = {
|
|
20
|
+
conversation_id: string;
|
|
21
|
+
user_id: string;
|
|
22
|
+
elphieSessionId: string;
|
|
23
|
+
firstTurn: ElphieMessageTurn;
|
|
24
|
+
};
|
|
25
|
+
export declare const ElphieMessageModel: import("dynamoose/dist/General").ModelType<ElphieMessage>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ElphieMessageModel = exports.ELPHIE_MESSAGE_ROLE = void 0;
|
|
7
|
+
const dynamoose_1 = __importDefault(require("dynamoose"));
|
|
8
|
+
const table_names_1 = require("../../config/table-names");
|
|
9
|
+
exports.ELPHIE_MESSAGE_ROLE = {
|
|
10
|
+
USER: "user",
|
|
11
|
+
ELPHIE: "elphie"
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Dynamoose schema for `elphie_messages`.
|
|
15
|
+
*
|
|
16
|
+
* HASH: `conversation_id`.
|
|
17
|
+
* GSI `user_id-index`: HASH `user_id` only (`updated_at` is a plain attribute).
|
|
18
|
+
* GSI `elphieSessionId-index`: HASH `elphieSessionId` (links to `elphie_sessions`).
|
|
19
|
+
*
|
|
20
|
+
* `create: false` — tables + GSIs are provisioned via CDK, not auto-created on boot.
|
|
21
|
+
*/
|
|
22
|
+
const elphieMessageSchema = new dynamoose_1.default.Schema({
|
|
23
|
+
conversation_id: {
|
|
24
|
+
type: String,
|
|
25
|
+
hashKey: true,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
user_id: {
|
|
29
|
+
type: String,
|
|
30
|
+
required: true,
|
|
31
|
+
index: {
|
|
32
|
+
name: "user_id-index",
|
|
33
|
+
type: "global"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
elphieSessionId: {
|
|
37
|
+
type: String,
|
|
38
|
+
required: true,
|
|
39
|
+
index: {
|
|
40
|
+
name: "elphieSessionId-index",
|
|
41
|
+
type: "global"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
content: {
|
|
45
|
+
type: Array,
|
|
46
|
+
schema: [
|
|
47
|
+
{
|
|
48
|
+
type: Object,
|
|
49
|
+
schema: {
|
|
50
|
+
role: {
|
|
51
|
+
type: String,
|
|
52
|
+
required: true,
|
|
53
|
+
enum: [exports.ELPHIE_MESSAGE_ROLE.USER, exports.ELPHIE_MESSAGE_ROLE.ELPHIE]
|
|
54
|
+
},
|
|
55
|
+
text: {
|
|
56
|
+
type: String,
|
|
57
|
+
required: true
|
|
58
|
+
},
|
|
59
|
+
timestamp: {
|
|
60
|
+
type: String,
|
|
61
|
+
required: true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
required: true,
|
|
67
|
+
default: []
|
|
68
|
+
},
|
|
69
|
+
updated_at: {
|
|
70
|
+
type: String,
|
|
71
|
+
required: true
|
|
72
|
+
}
|
|
73
|
+
}, {
|
|
74
|
+
saveUnknown: false,
|
|
75
|
+
timestamps: true
|
|
76
|
+
});
|
|
77
|
+
exports.ElphieMessageModel = dynamoose_1.default.model(table_names_1.TABLE_NAMES.ELPHIE_MESSAGES, elphieMessageSchema, { create: false, waitForActive: false });
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxwaGllLW1lc3NhZ2UtbW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY3VzdG9tZXItdXNlci9lbHBoaWUvZWxwaGllLW1lc3NhZ2UtbW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMERBQWtDO0FBRWxDLDBEQUF1RDtBQUUxQyxRQUFBLG1CQUFtQixHQUFHO0lBQy9CLElBQUksRUFBRSxNQUFNO0lBQ1osTUFBTSxFQUFFLFFBQVE7Q0FDVixDQUFDO0FBeUJYOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLG1CQUFTLENBQUMsTUFBTSxDQUM1QztJQUNJLGVBQWUsRUFBRTtRQUNiLElBQUksRUFBRSxNQUFNO1FBQ1osT0FBTyxFQUFFLElBQUk7UUFDYixRQUFRLEVBQUUsSUFBSTtLQUNqQjtJQUNELE9BQU8sRUFBRTtRQUNMLElBQUksRUFBRSxNQUFNO1FBQ1osUUFBUSxFQUFFLElBQUk7UUFDZCxLQUFLLEVBQUU7WUFDSCxJQUFJLEVBQUUsZUFBZTtZQUNyQixJQUFJLEVBQUUsUUFBUTtTQUNqQjtLQUNKO0lBQ0QsZUFBZSxFQUFFO1FBQ2IsSUFBSSxFQUFFLE1BQU07UUFDWixRQUFRLEVBQUUsSUFBSTtRQUNkLEtBQUssRUFBRTtZQUNILElBQUksRUFBRSx1QkFBdUI7WUFDN0IsSUFBSSxFQUFFLFFBQVE7U0FDakI7S0FDSjtJQUNELE9BQU8sRUFBRTtRQUNMLElBQUksRUFBRSxLQUFLO1FBQ1gsTUFBTSxFQUFFO1lBQ0o7Z0JBQ0ksSUFBSSxFQUFFLE1BQU07Z0JBQ1osTUFBTSxFQUFFO29CQUNKLElBQUksRUFBRTt3QkFDRixJQUFJLEVBQUUsTUFBTTt3QkFDWixRQUFRLEVBQUUsSUFBSTt3QkFDZCxJQUFJLEVBQUUsQ0FBQywyQkFBbUIsQ0FBQyxJQUFJLEVBQUUsMkJBQW1CLENBQUMsTUFBTSxDQUFDO3FCQUMvRDtvQkFDRCxJQUFJLEVBQUU7d0JBQ0YsSUFBSSxFQUFFLE1BQU07d0JBQ1osUUFBUSxFQUFFLElBQUk7cUJBQ2pCO29CQUNELFNBQVMsRUFBRTt3QkFDUCxJQUFJLEVBQUUsTUFBTTt3QkFDWixRQUFRLEVBQUUsSUFBSTtxQkFDakI7aUJBQ0o7YUFDSjtTQUNKO1FBQ0QsUUFBUSxFQUFFLElBQUk7UUFDZCxPQUFPLEVBQUUsRUFBRTtLQUNkO0lBQ0QsVUFBVSxFQUFFO1FBQ1IsSUFBSSxFQUFFLE1BQU07UUFDWixRQUFRLEVBQUUsSUFBSTtLQUNqQjtDQUNKLEVBQ0Q7SUFDSSxXQUFXLEVBQUUsS0FBSztJQUNsQixVQUFVLEVBQUUsSUFBSTtDQUNuQixDQUNKLENBQUM7QUFFVyxRQUFBLGtCQUFrQixHQUFHLG1CQUFTLENBQUMsS0FBSyxDQUM3Qyx5QkFBVyxDQUFDLGVBQWUsRUFDM0IsbUJBQW1CLEVBQ25CLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLENBQzFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZHluYW1vb3NlIGZyb20gXCJkeW5hbW9vc2VcIjtcbmltcG9ydCB7IEl0ZW0gfSBmcm9tIFwiZHluYW1vb3NlL2Rpc3QvSXRlbVwiO1xuaW1wb3J0IHsgVEFCTEVfTkFNRVMgfSBmcm9tIFwiLi4vLi4vY29uZmlnL3RhYmxlLW5hbWVzXCI7XG5cbmV4cG9ydCBjb25zdCBFTFBISUVfTUVTU0FHRV9ST0xFID0ge1xuICAgIFVTRVI6IFwidXNlclwiLFxuICAgIEVMUEhJRTogXCJlbHBoaWVcIlxufSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgRWxwaGllTWVzc2FnZVJvbGUgPSAodHlwZW9mIEVMUEhJRV9NRVNTQUdFX1JPTEUpW2tleW9mIHR5cGVvZiBFTFBISUVfTUVTU0FHRV9ST0xFXTtcblxuZXhwb3J0IGludGVyZmFjZSBFbHBoaWVNZXNzYWdlVHVybiB7XG4gICAgcm9sZTogRWxwaGllTWVzc2FnZVJvbGU7XG4gICAgdGV4dDogc3RyaW5nO1xuICAgIHRpbWVzdGFtcDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVscGhpZU1lc3NhZ2UgZXh0ZW5kcyBJdGVtIHtcbiAgICBjb252ZXJzYXRpb25faWQ6IHN0cmluZztcbiAgICB1c2VyX2lkOiBzdHJpbmc7XG4gICAgZWxwaGllU2Vzc2lvbklkOiBzdHJpbmc7XG4gICAgY29udGVudDogRWxwaGllTWVzc2FnZVR1cm5bXTtcbiAgICB1cGRhdGVkX2F0OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIENyZWF0ZUVscGhpZUNvbnZlcnNhdGlvbklucHV0ID0ge1xuICAgIGNvbnZlcnNhdGlvbl9pZDogc3RyaW5nO1xuICAgIHVzZXJfaWQ6IHN0cmluZztcbiAgICBlbHBoaWVTZXNzaW9uSWQ6IHN0cmluZztcbiAgICBmaXJzdFR1cm46IEVscGhpZU1lc3NhZ2VUdXJuO1xufTtcblxuLyoqXG4gKiBEeW5hbW9vc2Ugc2NoZW1hIGZvciBgZWxwaGllX21lc3NhZ2VzYC5cbiAqXG4gKiBIQVNIOiBgY29udmVyc2F0aW9uX2lkYC5cbiAqIEdTSSBgdXNlcl9pZC1pbmRleGA6IEhBU0ggYHVzZXJfaWRgIG9ubHkgKGB1cGRhdGVkX2F0YCBpcyBhIHBsYWluIGF0dHJpYnV0ZSkuXG4gKiBHU0kgYGVscGhpZVNlc3Npb25JZC1pbmRleGA6IEhBU0ggYGVscGhpZVNlc3Npb25JZGAgKGxpbmtzIHRvIGBlbHBoaWVfc2Vzc2lvbnNgKS5cbiAqXG4gKiBgY3JlYXRlOiBmYWxzZWAg4oCUIHRhYmxlcyArIEdTSXMgYXJlIHByb3Zpc2lvbmVkIHZpYSBDREssIG5vdCBhdXRvLWNyZWF0ZWQgb24gYm9vdC5cbiAqL1xuY29uc3QgZWxwaGllTWVzc2FnZVNjaGVtYSA9IG5ldyBkeW5hbW9vc2UuU2NoZW1hKFxuICAgIHtcbiAgICAgICAgY29udmVyc2F0aW9uX2lkOiB7XG4gICAgICAgICAgICB0eXBlOiBTdHJpbmcsXG4gICAgICAgICAgICBoYXNoS2V5OiB0cnVlLFxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgdXNlcl9pZDoge1xuICAgICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgICBpbmRleDoge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwidXNlcl9pZC1pbmRleFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwiZ2xvYmFsXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZWxwaGllU2Vzc2lvbklkOiB7XG4gICAgICAgICAgICB0eXBlOiBTdHJpbmcsXG4gICAgICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgICAgIGluZGV4OiB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJlbHBoaWVTZXNzaW9uSWQtaW5kZXhcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcImdsb2JhbFwiXG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGNvbnRlbnQ6IHtcbiAgICAgICAgICAgIHR5cGU6IEFycmF5LFxuICAgICAgICAgICAgc2NoZW1hOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiBPYmplY3QsXG4gICAgICAgICAgICAgICAgICAgIHNjaGVtYToge1xuICAgICAgICAgICAgICAgICAgICAgICAgcm9sZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnVtOiBbRUxQSElFX01FU1NBR0VfUk9MRS5VU0VSLCBFTFBISUVfTUVTU0FHRV9ST0xFLkVMUEhJRV1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZXN0YW1wOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgICBkZWZhdWx0OiBbXVxuICAgICAgICB9LFxuICAgICAgICB1cGRhdGVkX2F0OiB7XG4gICAgICAgICAgICB0eXBlOiBTdHJpbmcsXG4gICAgICAgICAgICByZXF1aXJlZDogdHJ1ZVxuICAgICAgICB9XG4gICAgfSxcbiAgICB7XG4gICAgICAgIHNhdmVVbmtub3duOiBmYWxzZSxcbiAgICAgICAgdGltZXN0YW1wczogdHJ1ZVxuICAgIH1cbik7XG5cbmV4cG9ydCBjb25zdCBFbHBoaWVNZXNzYWdlTW9kZWwgPSBkeW5hbW9vc2UubW9kZWw8RWxwaGllTWVzc2FnZT4oXG4gICAgVEFCTEVfTkFNRVMuRUxQSElFX01FU1NBR0VTLFxuICAgIGVscGhpZU1lc3NhZ2VTY2hlbWEsXG4gICAgeyBjcmVhdGU6IGZhbHNlLCB3YWl0Rm9yQWN0aXZlOiBmYWxzZSB9XG4pO1xuIl19
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DynamoKey } from "../../base-dynamoose-dao";
|
|
2
|
+
import { CreateElphieSessionInput, ElphieSession } from "./elphie-session-model";
|
|
3
|
+
type ListResult = {
|
|
4
|
+
items: ElphieSession[];
|
|
5
|
+
lastKey?: DynamoKey;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Service/DAO for `elphie_sessions`.
|
|
9
|
+
*
|
|
10
|
+
* HASH: `elphieSessionId` (UUID set here — never schema-defaulted).
|
|
11
|
+
* List-by-user: GSI `user_id-index`.
|
|
12
|
+
*/
|
|
13
|
+
declare class ElphieSessionService {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a session. Generates `elphieSessionId` via `randomUUID()` and stamps ISO UTC times.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const session = await elphieSessionService.createSession({
|
|
19
|
+
* user_id: "user-1",
|
|
20
|
+
* conversation_id: "conv-1",
|
|
21
|
+
* title: "Birthday planning",
|
|
22
|
+
* fmp_context: { occasion: "birthday" }
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
createSession: (input: CreateElphieSessionInput) => Promise<ElphieSession>;
|
|
26
|
+
/**
|
|
27
|
+
* Fetches one session by `elphieSessionId`.
|
|
28
|
+
* Throws `SessionNotFoundError` when missing.
|
|
29
|
+
*/
|
|
30
|
+
getSessionById: (elphieSessionId: string) => Promise<ElphieSession>;
|
|
31
|
+
/**
|
|
32
|
+
* Lists sessions for a user via GSI `user_id-index`.
|
|
33
|
+
* Newest-first order is applied in memory on `created_at` (not a GSI range key).
|
|
34
|
+
* Pass `lastKey` from the previous response for pagination.
|
|
35
|
+
*/
|
|
36
|
+
listSessionsForUser: (user_id: string, { limit, lastKey }?: {
|
|
37
|
+
limit?: number;
|
|
38
|
+
lastKey?: DynamoKey;
|
|
39
|
+
}) => Promise<ListResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Atomically updates session `title` + `updated_at`.
|
|
42
|
+
*/
|
|
43
|
+
updateSessionTitle: (elphieSessionId: string, title: string) => Promise<ElphieSession>;
|
|
44
|
+
}
|
|
45
|
+
export declare const elphieSessionService: ElphieSessionService;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.elphieSessionService = void 0;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const dynamoose_1 = __importDefault(require("dynamoose"));
|
|
9
|
+
const elphie_errors_1 = require("./elphie-errors");
|
|
10
|
+
const elphie_session_model_1 = require("./elphie-session-model");
|
|
11
|
+
const nowIso = () => new Date().toISOString();
|
|
12
|
+
/**
|
|
13
|
+
* Service/DAO for `elphie_sessions`.
|
|
14
|
+
*
|
|
15
|
+
* HASH: `elphieSessionId` (UUID set here — never schema-defaulted).
|
|
16
|
+
* List-by-user: GSI `user_id-index`.
|
|
17
|
+
*/
|
|
18
|
+
class ElphieSessionService {
|
|
19
|
+
constructor() {
|
|
20
|
+
/**
|
|
21
|
+
* Creates a session. Generates `elphieSessionId` via `randomUUID()` and stamps ISO UTC times.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const session = await elphieSessionService.createSession({
|
|
25
|
+
* user_id: "user-1",
|
|
26
|
+
* conversation_id: "conv-1",
|
|
27
|
+
* title: "Birthday planning",
|
|
28
|
+
* fmp_context: { occasion: "birthday" }
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
this.createSession = async (input) => {
|
|
32
|
+
try {
|
|
33
|
+
const now = nowIso();
|
|
34
|
+
const created = await elphie_session_model_1.ElphieSessionModel.create({
|
|
35
|
+
elphieSessionId: (0, crypto_1.randomUUID)(),
|
|
36
|
+
user_id: input.user_id,
|
|
37
|
+
conversation_id: input.conversation_id,
|
|
38
|
+
title: input.title,
|
|
39
|
+
fmp_context: input.fmp_context,
|
|
40
|
+
created_at: now,
|
|
41
|
+
updated_at: now
|
|
42
|
+
});
|
|
43
|
+
return created;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
throw wrapUnexpected("createSession", error);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Fetches one session by `elphieSessionId`.
|
|
51
|
+
* Throws `SessionNotFoundError` when missing.
|
|
52
|
+
*/
|
|
53
|
+
this.getSessionById = async (elphieSessionId) => {
|
|
54
|
+
try {
|
|
55
|
+
const session = await elphie_session_model_1.ElphieSessionModel.get(elphieSessionId);
|
|
56
|
+
if (!session) {
|
|
57
|
+
throw new elphie_errors_1.SessionNotFoundError(elphieSessionId);
|
|
58
|
+
}
|
|
59
|
+
return session;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof elphie_errors_1.SessionNotFoundError) {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
// Dynamoose may throw ItemNotFoundError depending on settings
|
|
66
|
+
if (isNotFoundError(error)) {
|
|
67
|
+
throw new elphie_errors_1.SessionNotFoundError(elphieSessionId);
|
|
68
|
+
}
|
|
69
|
+
throw wrapUnexpected("getSessionById", error);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Lists sessions for a user via GSI `user_id-index`.
|
|
74
|
+
* Newest-first order is applied in memory on `created_at` (not a GSI range key).
|
|
75
|
+
* Pass `lastKey` from the previous response for pagination.
|
|
76
|
+
*/
|
|
77
|
+
this.listSessionsForUser = async (user_id, { limit, lastKey } = {}) => {
|
|
78
|
+
try {
|
|
79
|
+
let queryBuilder = elphie_session_model_1.ElphieSessionModel.query("user_id")
|
|
80
|
+
.eq(user_id)
|
|
81
|
+
.using("user_id-index");
|
|
82
|
+
if (lastKey) {
|
|
83
|
+
queryBuilder = queryBuilder.startAt(lastKey);
|
|
84
|
+
}
|
|
85
|
+
if (typeof limit === "number") {
|
|
86
|
+
queryBuilder = queryBuilder.limit(limit);
|
|
87
|
+
}
|
|
88
|
+
const queryResult = await queryBuilder.exec();
|
|
89
|
+
const items = [...queryResult].sort((a, b) => (b.created_at ?? "").localeCompare(a.created_at ?? ""));
|
|
90
|
+
return {
|
|
91
|
+
items,
|
|
92
|
+
lastKey: queryResult.lastKey
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw wrapUnexpected("listSessionsForUser", error);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Atomically updates session `title` + `updated_at`.
|
|
101
|
+
*/
|
|
102
|
+
this.updateSessionTitle = async (elphieSessionId, title) => {
|
|
103
|
+
try {
|
|
104
|
+
const updated = await elphie_session_model_1.ElphieSessionModel.update({ elphieSessionId }, {
|
|
105
|
+
title,
|
|
106
|
+
updated_at: nowIso()
|
|
107
|
+
}, {
|
|
108
|
+
condition: new dynamoose_1.default.Condition().attribute("elphieSessionId").exists()
|
|
109
|
+
});
|
|
110
|
+
return updated;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (isNotFoundError(error) || isConditionalCheckFailed(error)) {
|
|
114
|
+
throw new elphie_errors_1.SessionNotFoundError(elphieSessionId);
|
|
115
|
+
}
|
|
116
|
+
throw wrapUnexpected("updateSessionTitle", error);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const isNotFoundError = (error) => {
|
|
122
|
+
const name = error?.name;
|
|
123
|
+
return name === "ItemNotFoundException" || name === "ItemNotFoundError";
|
|
124
|
+
};
|
|
125
|
+
const isConditionalCheckFailed = (error) => {
|
|
126
|
+
const name = error?.name;
|
|
127
|
+
return name === "ConditionalCheckFailedException";
|
|
128
|
+
};
|
|
129
|
+
const wrapUnexpected = (operation, error) => {
|
|
130
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
131
|
+
return new Error(`ElphieSessionService.${operation} failed: ${message}`);
|
|
132
|
+
};
|
|
133
|
+
exports.elphieSessionService = new ElphieSessionService();
|
|
134
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxwaGllLXNlc3Npb24tZGFvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2N1c3RvbWVyLXVzZXIvZWxwaGllL2VscGhpZS1zZXNzaW9uLWRhby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxtQ0FBb0M7QUFDcEMsMERBQWtDO0FBRWxDLG1EQUF1RDtBQUN2RCxpRUFJZ0M7QUFPaEMsTUFBTSxNQUFNLEdBQUcsR0FBVyxFQUFFLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUV0RDs7Ozs7R0FLRztBQUNILE1BQU0sb0JBQW9CO0lBQTFCO1FBQ0k7Ozs7Ozs7Ozs7V0FVRztRQUNILGtCQUFhLEdBQUcsS0FBSyxFQUFFLEtBQStCLEVBQTBCLEVBQUU7WUFDOUUsSUFBSSxDQUFDO2dCQUNELE1BQU0sR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFDO2dCQUNyQixNQUFNLE9BQU8sR0FBRyxNQUFNLHlDQUFrQixDQUFDLE1BQU0sQ0FBQztvQkFDNUMsZUFBZSxFQUFFLElBQUEsbUJBQVUsR0FBRTtvQkFDN0IsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO29CQUN0QixlQUFlLEVBQUUsS0FBSyxDQUFDLGVBQWU7b0JBQ3RDLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSztvQkFDbEIsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO29CQUM5QixVQUFVLEVBQUUsR0FBRztvQkFDZixVQUFVLEVBQUUsR0FBRztpQkFDbEIsQ0FBQyxDQUFDO2dCQUNILE9BQU8sT0FBd0IsQ0FBQztZQUNwQyxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDYixNQUFNLGNBQWMsQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDakQsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUVGOzs7V0FHRztRQUNILG1CQUFjLEdBQUcsS0FBSyxFQUFFLGVBQXVCLEVBQTBCLEVBQUU7WUFDdkUsSUFBSSxD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QkFBb0IsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN0RCxDQUFDO1FBQ0wsQ0FBQyxDQUFDO0lBQ04sQ0FBQztDQUFBO0FBRUQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxLQUFjLEVBQVcsRUFBRTtJQUNoRCxNQUFNLElBQUksR0FBSSxLQUFrQyxFQUFFLElBQUksQ0FBQztJQUN2RCxPQUFPLElBQUksS0FBSyx1QkFBdUIsSUFBSSxJQUFJLEtBQUssbUJBQW1CLENBQUM7QUFDNUUsQ0FBQyxDQUFDO0FBRUYsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLEtBQWMsRUFBVyxFQUFFO0lBQ3pELE1BQU0sSUFBSSxHQUFJLEtBQWtDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZELE9BQU8sSUFBSSxLQUFLLGlDQUFpQyxDQUFDO0FBQ3RELENBQUMsQ0FBQztBQUVGLE1BQU0sY0FBYyxHQUFHLENBQUMsU0FBaUIsRUFBRSxLQUFjLEVBQVMsRUFBRTtJQUNoRSxNQUFNLE9BQU8sR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkUsT0FBTyxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsU0FBUyxZQUFZLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDN0UsQ0FBQyxDQUFDO0FBRVcsUUFBQSxvQkFBb0IsR0FBRyxJQUFJLG9CQUFvQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IGR5bmFtb29zZSBmcm9tIFwiZHluYW1vb3NlXCI7XG5pbXBvcnQgeyBEeW5hbW9LZXkgfSBmcm9tIFwiLi4vLi4vYmFzZS1keW5hbW9vc2UtZGFvXCI7XG5pbXBvcnQgeyBTZXNzaW9uTm90Rm91bmRFcnJvciB9IGZyb20gXCIuL2VscGhpZS1lcnJvcnNcIjtcbmltcG9ydCB7XG4gICAgQ3JlYXRlRWxwaGllU2Vzc2lvbklucHV0LFxuICAgIEVscGhpZVNlc3Npb24sXG4gICAgRWxwaGllU2Vzc2lvbk1vZGVsXG59IGZyb20gXCIuL2VscGhpZS1zZXNzaW9uLW1vZGVsXCI7XG5cbnR5cGUgTGlzdFJlc3VsdCA9IHtcbiAgICBpdGVtczogRWxwaGllU2Vzc2lvbltdO1xuICAgIGxhc3RLZXk/OiBEeW5hbW9LZXk7XG59O1xuXG5jb25zdCBub3dJc28gPSAoKTogc3RyaW5nID0+IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcblxuLyoqXG4gKiBTZXJ2aWNlL0RBTyBmb3IgYGVscGhpZV9zZXNzaW9uc2AuXG4gKlxuICogSEFTSDogYGVscGhpZVNlc3Npb25JZGAgKFVVSUQgc2V0IGhlcmUg4oCUIG5ldmVyIHNjaGVtYS1kZWZhdWx0ZWQpLlxuICogTGlzdC1ieS11c2VyOiBHU0kgYHVzZXJfaWQtaW5kZXhgLlxuICovXG5jbGFzcyBFbHBoaWVTZXNzaW9uU2VydmljZSB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHNlc3Npb24uIEdlbmVyYXRlcyBgZWxwaGllU2Vzc2lvbklkYCB2aWEgYHJhbmRvbVVVSUQoKWAgYW5kIHN0YW1wcyBJU08gVVRDIHRpbWVzLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBjb25zdCBzZXNzaW9uID0gYXdhaXQgZWxwaGllU2Vzc2lvblNlcnZpY2UuY3JlYXRlU2Vzc2lvbih7XG4gICAgICogICAgIHVzZXJfaWQ6IFwidXNlci0xXCIsXG4gICAgICogICAgIGNvbnZlcnNhdGlvbl9pZDogXCJjb252LTFcIixcbiAgICAgKiAgICAgdGl0bGU6IFwiQmlydGhkYXkgcGxhbm5pbmdcIixcbiAgICAgKiAgICAgZm1wX2NvbnRleHQ6IHsgb2NjYXNpb246IFwiYmlydGhkYXlcIiB9XG4gICAgICogfSk7XG4gICAgICovXG4gICAgY3JlYXRlU2Vzc2lvbiA9IGFzeW5jIChpbnB1dDogQ3JlYXRlRWxwaGllU2Vzc2lvbklucHV0KTogUHJvbWlzZTxFbHBoaWVTZXNzaW9uPiA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBub3cgPSBub3dJc28oKTtcbiAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCBFbHBoaWVTZXNzaW9uTW9kZWwuY3JlYXRlKHtcbiAgICAgICAgICAgICAgICBlbHBoaWVTZXNzaW9uSWQ6IHJhbmRvbVVVSUQoKSxcbiAgICAgICAgICAgICAgICB1c2VyX2lkOiBpbnB1dC51c2VyX2lkLFxuICAgICAgICAgICAgICAgIGNvbnZlcnNhdGlvbl9pZDogaW5wdXQuY29udmVyc2F0aW9uX2lkLFxuICAgICAgICAgICAgICAgIHRpdGxlOiBpbnB1dC50aXRsZSxcbiAgICAgICAgICAgICAgICBmbXBfY29udGV4dDogaW5wdXQuZm1wX2NvbnRleHQsXG4gICAgICAgICAgICAgICAgY3JlYXRlZF9hdDogbm93LFxuICAgICAgICAgICAgICAgIHVwZGF0ZWRfYXQ6IG5vd1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gY3JlYXRlZCBhcyBFbHBoaWVTZXNzaW9uO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhyb3cgd3JhcFVuZXhwZWN0ZWQoXCJjcmVhdGVTZXNzaW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGZXRjaGVzIG9uZSBzZXNzaW9uIGJ5IGBlbHBoaWVTZXNzaW9uSWRgLlxuICAgICAqIFRocm93cyBgU2Vzc2lvbk5vdEZvdW5kRXJyb3JgIHdoZW4gbWlzc2luZy5cbiAgICAgKi9cbiAgICBnZXRTZXNzaW9uQnlJZCA9IGFzeW5jIChlbHBoaWVTZXNzaW9uSWQ6IHN0cmluZyk6IFByb21pc2U8RWxwaGllU2Vzc2lvbj4gPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3Qgc2Vzc2lvbiA9IGF3YWl0IEVscGhpZVNlc3Npb25Nb2RlbC5nZXQoZWxwaGllU2Vzc2lvbklkKTtcbiAgICAgICAgICAgIGlmICghc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBTZXNzaW9uTm90Rm91bmRFcnJvcihlbHBoaWVTZXNzaW9uSWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHNlc3Npb24gYXMgRWxwaGllU2Vzc2lvbjtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlc3Npb25Ob3RGb3VuZEVycm9yKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBEeW5hbW9vc2UgbWF5IHRocm93IEl0ZW1Ob3RGb3VuZEVycm9yIGRlcGVuZGluZyBvbiBzZXR0aW5nc1xuICAgICAgICAgICAgaWYgKGlzTm90Rm91bmRFcnJvcihlcnJvcikpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgU2Vzc2lvbk5vdEZvdW5kRXJyb3IoZWxwaGllU2Vzc2lvbklkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IHdyYXBVbmV4cGVjdGVkKFwiZ2V0U2Vzc2lvbkJ5SWRcIiwgZXJyb3IpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIExpc3RzIHNlc3Npb25zIGZvciBhIHVzZXIgdmlhIEdTSSBgdXNlcl9pZC1pbmRleGAuXG4gICAgICogTmV3ZXN0LWZpcnN0IG9yZGVyIGlzIGFwcGxpZWQgaW4gbWVtb3J5IG9uIGBjcmVhdGVkX2F0YCAobm90IGEgR1NJIHJhbmdlIGtleSkuXG4gICAgICogUGFzcyBgbGFzdEtleWAgZnJvbSB0aGUgcHJldmlvdXMgcmVzcG9uc2UgZm9yIHBhZ2luYXRpb24uXG4gICAgICovXG4gICAgbGlzdFNlc3Npb25zRm9yVXNlciA9IGFzeW5jIChcbiAgICAgICAgdXNlcl9pZDogc3RyaW5nLFxuICAgICAgICB7IGxpbWl0LCBsYXN0S2V5IH06IHsgbGltaXQ/OiBudW1iZXI7IGxhc3RLZXk/OiBEeW5hbW9LZXkgfSA9IHt9XG4gICAgKTogUHJvbWlzZTxMaXN0UmVzdWx0PiA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgcXVlcnlCdWlsZGVyID0gRWxwaGllU2Vzc2lvbk1vZGVsLnF1ZXJ5KFwidXNlcl9pZFwiKVxuICAgICAgICAgICAgICAgIC5lcSh1c2VyX2lkKVxuICAgICAgICAgICAgICAgIC51c2luZyhcInVzZXJfaWQtaW5kZXhcIik7XG5cbiAgICAgICAgICAgIGlmIChsYXN0S2V5KSB7XG4gICAgICAgICAgICAgICAgcXVlcnlCdWlsZGVyID0gcXVlcnlCdWlsZGVyLnN0YXJ0QXQobGFzdEtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxpbWl0ID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgcXVlcnlCdWlsZGVyID0gcXVlcnlCdWlsZGVyLmxpbWl0KGxpbWl0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcXVlcnlSZXN1bHQgPSBhd2FpdCBxdWVyeUJ1aWxkZXIuZXhlYygpO1xuICAgICAgICAgICAgY29uc3QgaXRlbXMgPSBbLi4uKHF1ZXJ5UmVzdWx0IGFzIHVua25vd24gYXMgRWxwaGllU2Vzc2lvbltdKV0uc29ydCgoYSwgYikgPT5cbiAgICAgICAgICAgICAgICAoYi5jcmVhdGVkX2F0ID8/IFwiXCIpLmxvY2FsZUNvbXBhcmUoYS5jcmVhdGVkX2F0ID8/IFwiXCIpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBpdGVtcyxcbiAgICAgICAgICAgICAgICBsYXN0S2V5OiBxdWVyeVJlc3VsdC5sYXN0S2V5IGFzIER5bmFtb0tleSB8IHVuZGVmaW5lZFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRocm93IHdyYXBVbmV4cGVjdGVkKFwibGlzdFNlc3Npb25zRm9yVXNlclwiLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQXRvbWljYWxseSB1cGRhdGVzIHNlc3Npb24gYHRpdGxlYCArIGB1cGRhdGVkX2F0YC5cbiAgICAgKi9cbiAgICB1cGRhdGVTZXNzaW9uVGl0bGUgPSBhc3luYyAoZWxwaGllU2Vzc2lvbklkOiBzdHJpbmcsIHRpdGxlOiBzdHJpbmcpOiBQcm9taXNlPEVscGhpZVNlc3Npb24+ID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZWQgPSBhd2FpdCBFbHBoaWVTZXNzaW9uTW9kZWwudXBkYXRlKFxuICAgICAgICAgICAgICAgIHsgZWxwaGllU2Vzc2lvbklkIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZSxcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlZF9hdDogbm93SXNvKClcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29uZGl0aW9uOiBuZXcgZHluYW1vb3NlLkNvbmRpdGlvbigpLmF0dHJpYnV0ZShcImVscGhpZVNlc3Npb25JZFwiKS5leGlzdHMoKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4gdXBkYXRlZCBhcyB1bmtub3duIGFzIEVscGhpZVNlc3Npb247XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBpZiAoaXNOb3RGb3VuZEVycm9yKGVycm9yKSB8fCBpc0NvbmRpdGlvbmFsQ2hlY2tGYWlsZWQoZXJyb3IpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFNlc3Npb25Ob3RGb3VuZEVycm9yKGVscGhpZVNlc3Npb25JZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyB3cmFwVW5leHBlY3RlZChcInVwZGF0ZVNlc3Npb25UaXRsZVwiLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICB9O1xufVxuXG5jb25zdCBpc05vdEZvdW5kRXJyb3IgPSAoZXJyb3I6IHVua25vd24pOiBib29sZWFuID0+IHtcbiAgICBjb25zdCBuYW1lID0gKGVycm9yIGFzIHsgbmFtZT86IHN0cmluZyB9IHwgbnVsbCk/Lm5hbWU7XG4gICAgcmV0dXJuIG5hbWUgPT09IFwiSXRlbU5vdEZvdW5kRXhjZXB0aW9uXCIgfHwgbmFtZSA9PT0gXCJJdGVtTm90Rm91bmRFcnJvclwiO1xufTtcblxuY29uc3QgaXNDb25kaXRpb25hbENoZWNrRmFpbGVkID0gKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiA9PiB7XG4gICAgY29uc3QgbmFtZSA9IChlcnJvciBhcyB7IG5hbWU/OiBzdHJpbmcgfSB8IG51bGwpPy5uYW1lO1xuICAgIHJldHVybiBuYW1lID09PSBcIkNvbmRpdGlvbmFsQ2hlY2tGYWlsZWRFeGNlcHRpb25cIjtcbn07XG5cbmNvbnN0IHdyYXBVbmV4cGVjdGVkID0gKG9wZXJhdGlvbjogc3RyaW5nLCBlcnJvcjogdW5rbm93bik6IEVycm9yID0+IHtcbiAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICAgIHJldHVybiBuZXcgRXJyb3IoYEVscGhpZVNlc3Npb25TZXJ2aWNlLiR7b3BlcmF0aW9ufSBmYWlsZWQ6ICR7bWVzc2FnZX1gKTtcbn07XG5cbmV4cG9ydCBjb25zdCBlbHBoaWVTZXNzaW9uU2VydmljZSA9IG5ldyBFbHBoaWVTZXNzaW9uU2VydmljZSgpO1xuIl19
|