@stardeck-customer-apps/testing 0.3.0 → 0.3.1
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/index.js +95 -0
- package/dist/index.mjs +95 -0
- package/dist/next/headers-shim.js +1 -0
- package/dist/next/headers-shim.mjs +1 -0
- package/dist/setup.js +93 -0
- package/dist/setup.mjs +93 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99,6 +99,7 @@ var state = globalSingleton("state", () => ({
|
|
|
99
99
|
emailCounter: 0,
|
|
100
100
|
identities: /* @__PURE__ */ new Map(),
|
|
101
101
|
identityLinks: [],
|
|
102
|
+
identityMemory: [],
|
|
102
103
|
allowNetwork: false
|
|
103
104
|
}));
|
|
104
105
|
function requireDb() {
|
|
@@ -756,16 +757,108 @@ async function handleAttachLink(identityId, request) {
|
|
|
756
757
|
state.identityLinks.push(link);
|
|
757
758
|
return success({ link });
|
|
758
759
|
}
|
|
760
|
+
function memoryDto(m) {
|
|
761
|
+
return {
|
|
762
|
+
id: m.id,
|
|
763
|
+
source: m.source,
|
|
764
|
+
kind: m.kind,
|
|
765
|
+
content: m.content,
|
|
766
|
+
metadata: m.metadata,
|
|
767
|
+
createdAt: m.createdAt
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
async function handleResolve(request) {
|
|
771
|
+
const body = await readBody(request);
|
|
772
|
+
const type = body.type;
|
|
773
|
+
if (type !== "person" && type !== "account") {
|
|
774
|
+
return failure("type must be 'person' or 'account'");
|
|
775
|
+
}
|
|
776
|
+
if (type === "account") {
|
|
777
|
+
return failure(
|
|
778
|
+
"resolveOrCreate is for channel-linked persons; an account is not resolvable by link \u2014 create it explicitly instead.",
|
|
779
|
+
409
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
const link = body.link;
|
|
783
|
+
const kind = link?.kind;
|
|
784
|
+
const externalId = link?.externalId;
|
|
785
|
+
if (typeof kind !== "string" || !LINK_KINDS.has(kind)) {
|
|
786
|
+
return failure(`link.kind must be one of: ${[...LINK_KINDS].join(", ")}`);
|
|
787
|
+
}
|
|
788
|
+
if (typeof externalId !== "string" || !externalId) {
|
|
789
|
+
return failure("link.externalId is required");
|
|
790
|
+
}
|
|
791
|
+
const existingLink = state.identityLinks.find(
|
|
792
|
+
(l) => l.kind === kind && l.externalId === externalId
|
|
793
|
+
);
|
|
794
|
+
if (existingLink) {
|
|
795
|
+
const identity2 = state.identities.get(existingLink.identityId);
|
|
796
|
+
if (identity2) return success({ identity: identity2, created: false });
|
|
797
|
+
}
|
|
798
|
+
const identity = {
|
|
799
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
800
|
+
type,
|
|
801
|
+
parentId: null,
|
|
802
|
+
displayName: body.displayName ?? null,
|
|
803
|
+
profile: body.profile ?? {},
|
|
804
|
+
status: "active",
|
|
805
|
+
mergedIntoId: null,
|
|
806
|
+
externalRef: null,
|
|
807
|
+
createdAt: now(),
|
|
808
|
+
updatedAt: now()
|
|
809
|
+
};
|
|
810
|
+
state.identities.set(identity.id, identity);
|
|
811
|
+
state.identityLinks.push({
|
|
812
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
813
|
+
identityId: identity.id,
|
|
814
|
+
kind,
|
|
815
|
+
externalId,
|
|
816
|
+
verified: true,
|
|
817
|
+
createdAt: now()
|
|
818
|
+
});
|
|
819
|
+
return success({ identity, created: true });
|
|
820
|
+
}
|
|
821
|
+
async function handleWriteMemory(identityId, request) {
|
|
822
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
823
|
+
const body = await readBody(request);
|
|
824
|
+
if (typeof body.content !== "string" || !body.content) return failure("content is required");
|
|
825
|
+
const entry = {
|
|
826
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
827
|
+
identityId,
|
|
828
|
+
source: typeof body.source === "string" ? body.source : "app",
|
|
829
|
+
kind: typeof body.kind === "string" ? body.kind : "fact",
|
|
830
|
+
content: body.content,
|
|
831
|
+
metadata: body.metadata ?? {},
|
|
832
|
+
createdAt: now()
|
|
833
|
+
};
|
|
834
|
+
state.identityMemory.push(entry);
|
|
835
|
+
return success({ memory: memoryDto(entry) });
|
|
836
|
+
}
|
|
837
|
+
function handleListMemory(identityId, request) {
|
|
838
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
839
|
+
let rows = state.identityMemory.filter((m) => m.identityId === identityId).reverse();
|
|
840
|
+
const limitParam = new URL(request.url).searchParams.get("limit");
|
|
841
|
+
if (limitParam) rows = rows.slice(0, Math.max(1, parseInt(limitParam, 10) || 0));
|
|
842
|
+
return success({ memories: rows.map(memoryDto) });
|
|
843
|
+
}
|
|
759
844
|
async function handleIdentitiesRequest(request, subPath) {
|
|
760
845
|
const method = request.method;
|
|
761
846
|
if (subPath === "" || subPath === "/") {
|
|
762
847
|
if (method === "GET") return handleList(request);
|
|
763
848
|
if (method === "POST") return handleCreate(request);
|
|
764
849
|
}
|
|
850
|
+
if (subPath === "/resolve" && method === "POST") {
|
|
851
|
+
return handleResolve(request);
|
|
852
|
+
}
|
|
765
853
|
const linksMatch = subPath.match(/^\/([^/]+)\/links$/);
|
|
766
854
|
if (linksMatch && method === "POST") {
|
|
767
855
|
return handleAttachLink(linksMatch[1], request);
|
|
768
856
|
}
|
|
857
|
+
const memoryMatch = subPath.match(/^\/([^/]+)\/memory$/);
|
|
858
|
+
if (memoryMatch) {
|
|
859
|
+
if (method === "GET") return handleListMemory(memoryMatch[1], request);
|
|
860
|
+
if (method === "POST") return handleWriteMemory(memoryMatch[1], request);
|
|
861
|
+
}
|
|
769
862
|
const singleMatch = subPath.match(/^\/([^/]+)$/);
|
|
770
863
|
if (singleMatch) {
|
|
771
864
|
if (method === "GET") return handleGet(singleMatch[1]);
|
|
@@ -965,6 +1058,7 @@ async function createTestApp(options = {}) {
|
|
|
965
1058
|
state.emailCounter = 0;
|
|
966
1059
|
state.identities.clear();
|
|
967
1060
|
state.identityLinks = [];
|
|
1061
|
+
state.identityMemory = [];
|
|
968
1062
|
},
|
|
969
1063
|
async close() {
|
|
970
1064
|
state.db = null;
|
|
@@ -974,6 +1068,7 @@ async function createTestApp(options = {}) {
|
|
|
974
1068
|
state.emails = [];
|
|
975
1069
|
state.identities.clear();
|
|
976
1070
|
state.identityLinks = [];
|
|
1071
|
+
state.identityMemory = [];
|
|
977
1072
|
uninstallFetchRouter();
|
|
978
1073
|
await db.close();
|
|
979
1074
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -54,6 +54,7 @@ var state = globalSingleton("state", () => ({
|
|
|
54
54
|
emailCounter: 0,
|
|
55
55
|
identities: /* @__PURE__ */ new Map(),
|
|
56
56
|
identityLinks: [],
|
|
57
|
+
identityMemory: [],
|
|
57
58
|
allowNetwork: false
|
|
58
59
|
}));
|
|
59
60
|
function requireDb() {
|
|
@@ -711,16 +712,108 @@ async function handleAttachLink(identityId, request) {
|
|
|
711
712
|
state.identityLinks.push(link);
|
|
712
713
|
return success({ link });
|
|
713
714
|
}
|
|
715
|
+
function memoryDto(m) {
|
|
716
|
+
return {
|
|
717
|
+
id: m.id,
|
|
718
|
+
source: m.source,
|
|
719
|
+
kind: m.kind,
|
|
720
|
+
content: m.content,
|
|
721
|
+
metadata: m.metadata,
|
|
722
|
+
createdAt: m.createdAt
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
async function handleResolve(request) {
|
|
726
|
+
const body = await readBody(request);
|
|
727
|
+
const type = body.type;
|
|
728
|
+
if (type !== "person" && type !== "account") {
|
|
729
|
+
return failure("type must be 'person' or 'account'");
|
|
730
|
+
}
|
|
731
|
+
if (type === "account") {
|
|
732
|
+
return failure(
|
|
733
|
+
"resolveOrCreate is for channel-linked persons; an account is not resolvable by link \u2014 create it explicitly instead.",
|
|
734
|
+
409
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
const link = body.link;
|
|
738
|
+
const kind = link?.kind;
|
|
739
|
+
const externalId = link?.externalId;
|
|
740
|
+
if (typeof kind !== "string" || !LINK_KINDS.has(kind)) {
|
|
741
|
+
return failure(`link.kind must be one of: ${[...LINK_KINDS].join(", ")}`);
|
|
742
|
+
}
|
|
743
|
+
if (typeof externalId !== "string" || !externalId) {
|
|
744
|
+
return failure("link.externalId is required");
|
|
745
|
+
}
|
|
746
|
+
const existingLink = state.identityLinks.find(
|
|
747
|
+
(l) => l.kind === kind && l.externalId === externalId
|
|
748
|
+
);
|
|
749
|
+
if (existingLink) {
|
|
750
|
+
const identity2 = state.identities.get(existingLink.identityId);
|
|
751
|
+
if (identity2) return success({ identity: identity2, created: false });
|
|
752
|
+
}
|
|
753
|
+
const identity = {
|
|
754
|
+
id: crypto3.randomUUID(),
|
|
755
|
+
type,
|
|
756
|
+
parentId: null,
|
|
757
|
+
displayName: body.displayName ?? null,
|
|
758
|
+
profile: body.profile ?? {},
|
|
759
|
+
status: "active",
|
|
760
|
+
mergedIntoId: null,
|
|
761
|
+
externalRef: null,
|
|
762
|
+
createdAt: now(),
|
|
763
|
+
updatedAt: now()
|
|
764
|
+
};
|
|
765
|
+
state.identities.set(identity.id, identity);
|
|
766
|
+
state.identityLinks.push({
|
|
767
|
+
id: crypto3.randomUUID(),
|
|
768
|
+
identityId: identity.id,
|
|
769
|
+
kind,
|
|
770
|
+
externalId,
|
|
771
|
+
verified: true,
|
|
772
|
+
createdAt: now()
|
|
773
|
+
});
|
|
774
|
+
return success({ identity, created: true });
|
|
775
|
+
}
|
|
776
|
+
async function handleWriteMemory(identityId, request) {
|
|
777
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
778
|
+
const body = await readBody(request);
|
|
779
|
+
if (typeof body.content !== "string" || !body.content) return failure("content is required");
|
|
780
|
+
const entry = {
|
|
781
|
+
id: crypto3.randomUUID(),
|
|
782
|
+
identityId,
|
|
783
|
+
source: typeof body.source === "string" ? body.source : "app",
|
|
784
|
+
kind: typeof body.kind === "string" ? body.kind : "fact",
|
|
785
|
+
content: body.content,
|
|
786
|
+
metadata: body.metadata ?? {},
|
|
787
|
+
createdAt: now()
|
|
788
|
+
};
|
|
789
|
+
state.identityMemory.push(entry);
|
|
790
|
+
return success({ memory: memoryDto(entry) });
|
|
791
|
+
}
|
|
792
|
+
function handleListMemory(identityId, request) {
|
|
793
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
794
|
+
let rows = state.identityMemory.filter((m) => m.identityId === identityId).reverse();
|
|
795
|
+
const limitParam = new URL(request.url).searchParams.get("limit");
|
|
796
|
+
if (limitParam) rows = rows.slice(0, Math.max(1, parseInt(limitParam, 10) || 0));
|
|
797
|
+
return success({ memories: rows.map(memoryDto) });
|
|
798
|
+
}
|
|
714
799
|
async function handleIdentitiesRequest(request, subPath) {
|
|
715
800
|
const method = request.method;
|
|
716
801
|
if (subPath === "" || subPath === "/") {
|
|
717
802
|
if (method === "GET") return handleList(request);
|
|
718
803
|
if (method === "POST") return handleCreate(request);
|
|
719
804
|
}
|
|
805
|
+
if (subPath === "/resolve" && method === "POST") {
|
|
806
|
+
return handleResolve(request);
|
|
807
|
+
}
|
|
720
808
|
const linksMatch = subPath.match(/^\/([^/]+)\/links$/);
|
|
721
809
|
if (linksMatch && method === "POST") {
|
|
722
810
|
return handleAttachLink(linksMatch[1], request);
|
|
723
811
|
}
|
|
812
|
+
const memoryMatch = subPath.match(/^\/([^/]+)\/memory$/);
|
|
813
|
+
if (memoryMatch) {
|
|
814
|
+
if (method === "GET") return handleListMemory(memoryMatch[1], request);
|
|
815
|
+
if (method === "POST") return handleWriteMemory(memoryMatch[1], request);
|
|
816
|
+
}
|
|
724
817
|
const singleMatch = subPath.match(/^\/([^/]+)$/);
|
|
725
818
|
if (singleMatch) {
|
|
726
819
|
if (method === "GET") return handleGet(singleMatch[1]);
|
|
@@ -920,6 +1013,7 @@ async function createTestApp(options = {}) {
|
|
|
920
1013
|
state.emailCounter = 0;
|
|
921
1014
|
state.identities.clear();
|
|
922
1015
|
state.identityLinks = [];
|
|
1016
|
+
state.identityMemory = [];
|
|
923
1017
|
},
|
|
924
1018
|
async close() {
|
|
925
1019
|
state.db = null;
|
|
@@ -929,6 +1023,7 @@ async function createTestApp(options = {}) {
|
|
|
929
1023
|
state.emails = [];
|
|
930
1024
|
state.identities.clear();
|
|
931
1025
|
state.identityLinks = [];
|
|
1026
|
+
state.identityMemory = [];
|
|
932
1027
|
uninstallFetchRouter();
|
|
933
1028
|
await db.close();
|
|
934
1029
|
}
|
package/dist/setup.js
CHANGED
|
@@ -40,6 +40,7 @@ var state = globalSingleton("state", () => ({
|
|
|
40
40
|
emailCounter: 0,
|
|
41
41
|
identities: /* @__PURE__ */ new Map(),
|
|
42
42
|
identityLinks: [],
|
|
43
|
+
identityMemory: [],
|
|
43
44
|
allowNetwork: false
|
|
44
45
|
}));
|
|
45
46
|
function requireDb() {
|
|
@@ -687,16 +688,108 @@ async function handleAttachLink(identityId, request) {
|
|
|
687
688
|
state.identityLinks.push(link);
|
|
688
689
|
return success({ link });
|
|
689
690
|
}
|
|
691
|
+
function memoryDto(m) {
|
|
692
|
+
return {
|
|
693
|
+
id: m.id,
|
|
694
|
+
source: m.source,
|
|
695
|
+
kind: m.kind,
|
|
696
|
+
content: m.content,
|
|
697
|
+
metadata: m.metadata,
|
|
698
|
+
createdAt: m.createdAt
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
async function handleResolve(request) {
|
|
702
|
+
const body = await readBody(request);
|
|
703
|
+
const type = body.type;
|
|
704
|
+
if (type !== "person" && type !== "account") {
|
|
705
|
+
return failure("type must be 'person' or 'account'");
|
|
706
|
+
}
|
|
707
|
+
if (type === "account") {
|
|
708
|
+
return failure(
|
|
709
|
+
"resolveOrCreate is for channel-linked persons; an account is not resolvable by link \u2014 create it explicitly instead.",
|
|
710
|
+
409
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
const link = body.link;
|
|
714
|
+
const kind = link?.kind;
|
|
715
|
+
const externalId = link?.externalId;
|
|
716
|
+
if (typeof kind !== "string" || !LINK_KINDS.has(kind)) {
|
|
717
|
+
return failure(`link.kind must be one of: ${[...LINK_KINDS].join(", ")}`);
|
|
718
|
+
}
|
|
719
|
+
if (typeof externalId !== "string" || !externalId) {
|
|
720
|
+
return failure("link.externalId is required");
|
|
721
|
+
}
|
|
722
|
+
const existingLink = state.identityLinks.find(
|
|
723
|
+
(l) => l.kind === kind && l.externalId === externalId
|
|
724
|
+
);
|
|
725
|
+
if (existingLink) {
|
|
726
|
+
const identity2 = state.identities.get(existingLink.identityId);
|
|
727
|
+
if (identity2) return success({ identity: identity2, created: false });
|
|
728
|
+
}
|
|
729
|
+
const identity = {
|
|
730
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
731
|
+
type,
|
|
732
|
+
parentId: null,
|
|
733
|
+
displayName: body.displayName ?? null,
|
|
734
|
+
profile: body.profile ?? {},
|
|
735
|
+
status: "active",
|
|
736
|
+
mergedIntoId: null,
|
|
737
|
+
externalRef: null,
|
|
738
|
+
createdAt: now(),
|
|
739
|
+
updatedAt: now()
|
|
740
|
+
};
|
|
741
|
+
state.identities.set(identity.id, identity);
|
|
742
|
+
state.identityLinks.push({
|
|
743
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
744
|
+
identityId: identity.id,
|
|
745
|
+
kind,
|
|
746
|
+
externalId,
|
|
747
|
+
verified: true,
|
|
748
|
+
createdAt: now()
|
|
749
|
+
});
|
|
750
|
+
return success({ identity, created: true });
|
|
751
|
+
}
|
|
752
|
+
async function handleWriteMemory(identityId, request) {
|
|
753
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
754
|
+
const body = await readBody(request);
|
|
755
|
+
if (typeof body.content !== "string" || !body.content) return failure("content is required");
|
|
756
|
+
const entry = {
|
|
757
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
758
|
+
identityId,
|
|
759
|
+
source: typeof body.source === "string" ? body.source : "app",
|
|
760
|
+
kind: typeof body.kind === "string" ? body.kind : "fact",
|
|
761
|
+
content: body.content,
|
|
762
|
+
metadata: body.metadata ?? {},
|
|
763
|
+
createdAt: now()
|
|
764
|
+
};
|
|
765
|
+
state.identityMemory.push(entry);
|
|
766
|
+
return success({ memory: memoryDto(entry) });
|
|
767
|
+
}
|
|
768
|
+
function handleListMemory(identityId, request) {
|
|
769
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
770
|
+
let rows = state.identityMemory.filter((m) => m.identityId === identityId).reverse();
|
|
771
|
+
const limitParam = new URL(request.url).searchParams.get("limit");
|
|
772
|
+
if (limitParam) rows = rows.slice(0, Math.max(1, parseInt(limitParam, 10) || 0));
|
|
773
|
+
return success({ memories: rows.map(memoryDto) });
|
|
774
|
+
}
|
|
690
775
|
async function handleIdentitiesRequest(request, subPath) {
|
|
691
776
|
const method = request.method;
|
|
692
777
|
if (subPath === "" || subPath === "/") {
|
|
693
778
|
if (method === "GET") return handleList(request);
|
|
694
779
|
if (method === "POST") return handleCreate(request);
|
|
695
780
|
}
|
|
781
|
+
if (subPath === "/resolve" && method === "POST") {
|
|
782
|
+
return handleResolve(request);
|
|
783
|
+
}
|
|
696
784
|
const linksMatch = subPath.match(/^\/([^/]+)\/links$/);
|
|
697
785
|
if (linksMatch && method === "POST") {
|
|
698
786
|
return handleAttachLink(linksMatch[1], request);
|
|
699
787
|
}
|
|
788
|
+
const memoryMatch = subPath.match(/^\/([^/]+)\/memory$/);
|
|
789
|
+
if (memoryMatch) {
|
|
790
|
+
if (method === "GET") return handleListMemory(memoryMatch[1], request);
|
|
791
|
+
if (method === "POST") return handleWriteMemory(memoryMatch[1], request);
|
|
792
|
+
}
|
|
700
793
|
const singleMatch = subPath.match(/^\/([^/]+)$/);
|
|
701
794
|
if (singleMatch) {
|
|
702
795
|
if (method === "GET") return handleGet(singleMatch[1]);
|
package/dist/setup.mjs
CHANGED
|
@@ -16,6 +16,7 @@ var state = globalSingleton("state", () => ({
|
|
|
16
16
|
emailCounter: 0,
|
|
17
17
|
identities: /* @__PURE__ */ new Map(),
|
|
18
18
|
identityLinks: [],
|
|
19
|
+
identityMemory: [],
|
|
19
20
|
allowNetwork: false
|
|
20
21
|
}));
|
|
21
22
|
function requireDb() {
|
|
@@ -663,16 +664,108 @@ async function handleAttachLink(identityId, request) {
|
|
|
663
664
|
state.identityLinks.push(link);
|
|
664
665
|
return success({ link });
|
|
665
666
|
}
|
|
667
|
+
function memoryDto(m) {
|
|
668
|
+
return {
|
|
669
|
+
id: m.id,
|
|
670
|
+
source: m.source,
|
|
671
|
+
kind: m.kind,
|
|
672
|
+
content: m.content,
|
|
673
|
+
metadata: m.metadata,
|
|
674
|
+
createdAt: m.createdAt
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
async function handleResolve(request) {
|
|
678
|
+
const body = await readBody(request);
|
|
679
|
+
const type = body.type;
|
|
680
|
+
if (type !== "person" && type !== "account") {
|
|
681
|
+
return failure("type must be 'person' or 'account'");
|
|
682
|
+
}
|
|
683
|
+
if (type === "account") {
|
|
684
|
+
return failure(
|
|
685
|
+
"resolveOrCreate is for channel-linked persons; an account is not resolvable by link \u2014 create it explicitly instead.",
|
|
686
|
+
409
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
const link = body.link;
|
|
690
|
+
const kind = link?.kind;
|
|
691
|
+
const externalId = link?.externalId;
|
|
692
|
+
if (typeof kind !== "string" || !LINK_KINDS.has(kind)) {
|
|
693
|
+
return failure(`link.kind must be one of: ${[...LINK_KINDS].join(", ")}`);
|
|
694
|
+
}
|
|
695
|
+
if (typeof externalId !== "string" || !externalId) {
|
|
696
|
+
return failure("link.externalId is required");
|
|
697
|
+
}
|
|
698
|
+
const existingLink = state.identityLinks.find(
|
|
699
|
+
(l) => l.kind === kind && l.externalId === externalId
|
|
700
|
+
);
|
|
701
|
+
if (existingLink) {
|
|
702
|
+
const identity2 = state.identities.get(existingLink.identityId);
|
|
703
|
+
if (identity2) return success({ identity: identity2, created: false });
|
|
704
|
+
}
|
|
705
|
+
const identity = {
|
|
706
|
+
id: crypto3.randomUUID(),
|
|
707
|
+
type,
|
|
708
|
+
parentId: null,
|
|
709
|
+
displayName: body.displayName ?? null,
|
|
710
|
+
profile: body.profile ?? {},
|
|
711
|
+
status: "active",
|
|
712
|
+
mergedIntoId: null,
|
|
713
|
+
externalRef: null,
|
|
714
|
+
createdAt: now(),
|
|
715
|
+
updatedAt: now()
|
|
716
|
+
};
|
|
717
|
+
state.identities.set(identity.id, identity);
|
|
718
|
+
state.identityLinks.push({
|
|
719
|
+
id: crypto3.randomUUID(),
|
|
720
|
+
identityId: identity.id,
|
|
721
|
+
kind,
|
|
722
|
+
externalId,
|
|
723
|
+
verified: true,
|
|
724
|
+
createdAt: now()
|
|
725
|
+
});
|
|
726
|
+
return success({ identity, created: true });
|
|
727
|
+
}
|
|
728
|
+
async function handleWriteMemory(identityId, request) {
|
|
729
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
730
|
+
const body = await readBody(request);
|
|
731
|
+
if (typeof body.content !== "string" || !body.content) return failure("content is required");
|
|
732
|
+
const entry = {
|
|
733
|
+
id: crypto3.randomUUID(),
|
|
734
|
+
identityId,
|
|
735
|
+
source: typeof body.source === "string" ? body.source : "app",
|
|
736
|
+
kind: typeof body.kind === "string" ? body.kind : "fact",
|
|
737
|
+
content: body.content,
|
|
738
|
+
metadata: body.metadata ?? {},
|
|
739
|
+
createdAt: now()
|
|
740
|
+
};
|
|
741
|
+
state.identityMemory.push(entry);
|
|
742
|
+
return success({ memory: memoryDto(entry) });
|
|
743
|
+
}
|
|
744
|
+
function handleListMemory(identityId, request) {
|
|
745
|
+
if (!state.identities.get(identityId)) return failure("Identity not found", 404);
|
|
746
|
+
let rows = state.identityMemory.filter((m) => m.identityId === identityId).reverse();
|
|
747
|
+
const limitParam = new URL(request.url).searchParams.get("limit");
|
|
748
|
+
if (limitParam) rows = rows.slice(0, Math.max(1, parseInt(limitParam, 10) || 0));
|
|
749
|
+
return success({ memories: rows.map(memoryDto) });
|
|
750
|
+
}
|
|
666
751
|
async function handleIdentitiesRequest(request, subPath) {
|
|
667
752
|
const method = request.method;
|
|
668
753
|
if (subPath === "" || subPath === "/") {
|
|
669
754
|
if (method === "GET") return handleList(request);
|
|
670
755
|
if (method === "POST") return handleCreate(request);
|
|
671
756
|
}
|
|
757
|
+
if (subPath === "/resolve" && method === "POST") {
|
|
758
|
+
return handleResolve(request);
|
|
759
|
+
}
|
|
672
760
|
const linksMatch = subPath.match(/^\/([^/]+)\/links$/);
|
|
673
761
|
if (linksMatch && method === "POST") {
|
|
674
762
|
return handleAttachLink(linksMatch[1], request);
|
|
675
763
|
}
|
|
764
|
+
const memoryMatch = subPath.match(/^\/([^/]+)\/memory$/);
|
|
765
|
+
if (memoryMatch) {
|
|
766
|
+
if (method === "GET") return handleListMemory(memoryMatch[1], request);
|
|
767
|
+
if (method === "POST") return handleWriteMemory(memoryMatch[1], request);
|
|
768
|
+
}
|
|
676
769
|
const singleMatch = subPath.match(/^\/([^/]+)$/);
|
|
677
770
|
if (singleMatch) {
|
|
678
771
|
if (method === "GET") return handleGet(singleMatch[1]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardeck-customer-apps/testing",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Vitest test harness for Stardeck customer apps — in-process Postgres (PGlite) plus a control-plane simulator so the real Stardeck SDKs run unmodified in tests",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|