@stardeck-customer-apps/testing 0.6.0 → 0.6.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/SKILL.md CHANGED
@@ -215,10 +215,13 @@ describe the code, and the owner can't tell from them what is or isn't covered.
215
215
  - `client.identities` from integrations-sdk (create/get/update/list accounts &
216
216
  persons, attach channel links, guest/staff `resolveOrCreate`, paginated
217
217
  `search`, and batch `getAliases`) — served offline by the simulated directory.
218
- `resolveOrCreate` lowercases/trims email, requires E.164 phone values, and
218
+ `resolveOrCreate` applies the production email contract (trim + ASCII-only
219
+ A–Z→a–z; Turkish İ is left unchanged), requires E.164 phone values, and
219
220
  always writes an unverified link. A guest lookup of a verified link returns
220
221
  `{ identityId: null, reason: "verified_conflict" }`; staff provenance may
221
- resolve either verified or unverified links. `attachLink(..., { verified:
222
+ resolve either verified or unverified links. `attachLink` accepts only
223
+ channel kinds (line/facebook/instagram/email/phone); login keys must be
224
+ seeded via `app.identities.seedVerifiedLink`. `attachLink(..., { verified:
222
225
  true })` remains source-compatible but the simulator (like the control plane)
223
226
  ignores that flag and returns `verified: false`. `update` replaces the
224
227
  `profile` object (not a merge), like the control plane. Inspect via
package/dist/index.js CHANGED
@@ -679,7 +679,8 @@ function createInbox() {
679
679
 
680
680
  // src/simulator/identities.ts
681
681
  var import_node_crypto3 = __toESM(require("crypto"));
682
- var LINK_KINDS = /* @__PURE__ */ new Set([
682
+ var ATTACH_LINK_KINDS = /* @__PURE__ */ new Set(["line", "facebook", "instagram", "email", "phone"]);
683
+ var TRUSTED_LINK_KINDS = /* @__PURE__ */ new Set([
683
684
  "line",
684
685
  "facebook",
685
686
  "instagram",
@@ -692,6 +693,15 @@ var RESOLVE_KINDS = /* @__PURE__ */ new Set(["phone", "email", "line"]);
692
693
  var E164_PHONE = /^\+[1-9]\d{1,14}$/;
693
694
  var SEARCH_DEFAULT_LIMIT = 50;
694
695
  var SEARCH_MAX_LIMIT = 100;
696
+ function asciiLowercaseTrim(value) {
697
+ const trimmed = value.trim();
698
+ let out = "";
699
+ for (let i = 0; i < trimmed.length; i++) {
700
+ const code = trimmed.charCodeAt(i);
701
+ out += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : trimmed[i];
702
+ }
703
+ return out;
704
+ }
695
705
  var IdentityGraphError = class extends Error {
696
706
  };
697
707
  function now() {
@@ -701,12 +711,12 @@ function linksFor(identityId) {
701
711
  return state.identityLinks.filter((l) => l.identityId === identityId);
702
712
  }
703
713
  function comparableExternalId(kind, externalId) {
704
- if (kind === "email") return externalId.trim().toLowerCase();
714
+ if (kind === "email") return asciiLowercaseTrim(externalId);
705
715
  return externalId;
706
716
  }
707
717
  function normalizeExternalId(kind, externalId) {
708
718
  if (kind === "email") {
709
- const normalized = externalId.trim().toLowerCase();
719
+ const normalized = asciiLowercaseTrim(externalId);
710
720
  return normalized.length > 0 ? { externalId: normalized } : { error: "externalId is required" };
711
721
  }
712
722
  if (kind === "phone" && !E164_PHONE.test(externalId)) {
@@ -870,8 +880,8 @@ async function handleAttachLink(identityId, request) {
870
880
  const normalized = normalizeLinkInput(
871
881
  body.kind,
872
882
  body.externalId,
873
- LINK_KINDS,
874
- `kind must be one of: ${[...LINK_KINDS].join(", ")}`
883
+ ATTACH_LINK_KINDS,
884
+ `kind must be one of: ${[...ATTACH_LINK_KINDS].join(", ")}`
875
885
  );
876
886
  if ("error" in normalized) return failure(normalized.error);
877
887
  const { kind, externalId } = normalized;
@@ -1046,7 +1056,7 @@ function seedVerifiedLink(identityId, params) {
1046
1056
  const normalized = normalizeLinkInput(
1047
1057
  params.kind,
1048
1058
  params.externalId,
1049
- LINK_KINDS,
1059
+ TRUSTED_LINK_KINDS,
1050
1060
  "unknown identity link kind"
1051
1061
  );
1052
1062
  if ("error" in normalized) throw new Error(normalized.error);
package/dist/index.mjs CHANGED
@@ -633,7 +633,8 @@ function createInbox() {
633
633
 
634
634
  // src/simulator/identities.ts
635
635
  import crypto3 from "crypto";
636
- var LINK_KINDS = /* @__PURE__ */ new Set([
636
+ var ATTACH_LINK_KINDS = /* @__PURE__ */ new Set(["line", "facebook", "instagram", "email", "phone"]);
637
+ var TRUSTED_LINK_KINDS = /* @__PURE__ */ new Set([
637
638
  "line",
638
639
  "facebook",
639
640
  "instagram",
@@ -646,6 +647,15 @@ var RESOLVE_KINDS = /* @__PURE__ */ new Set(["phone", "email", "line"]);
646
647
  var E164_PHONE = /^\+[1-9]\d{1,14}$/;
647
648
  var SEARCH_DEFAULT_LIMIT = 50;
648
649
  var SEARCH_MAX_LIMIT = 100;
650
+ function asciiLowercaseTrim(value) {
651
+ const trimmed = value.trim();
652
+ let out = "";
653
+ for (let i = 0; i < trimmed.length; i++) {
654
+ const code = trimmed.charCodeAt(i);
655
+ out += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : trimmed[i];
656
+ }
657
+ return out;
658
+ }
649
659
  var IdentityGraphError = class extends Error {
650
660
  };
651
661
  function now() {
@@ -655,12 +665,12 @@ function linksFor(identityId) {
655
665
  return state.identityLinks.filter((l) => l.identityId === identityId);
656
666
  }
657
667
  function comparableExternalId(kind, externalId) {
658
- if (kind === "email") return externalId.trim().toLowerCase();
668
+ if (kind === "email") return asciiLowercaseTrim(externalId);
659
669
  return externalId;
660
670
  }
661
671
  function normalizeExternalId(kind, externalId) {
662
672
  if (kind === "email") {
663
- const normalized = externalId.trim().toLowerCase();
673
+ const normalized = asciiLowercaseTrim(externalId);
664
674
  return normalized.length > 0 ? { externalId: normalized } : { error: "externalId is required" };
665
675
  }
666
676
  if (kind === "phone" && !E164_PHONE.test(externalId)) {
@@ -824,8 +834,8 @@ async function handleAttachLink(identityId, request) {
824
834
  const normalized = normalizeLinkInput(
825
835
  body.kind,
826
836
  body.externalId,
827
- LINK_KINDS,
828
- `kind must be one of: ${[...LINK_KINDS].join(", ")}`
837
+ ATTACH_LINK_KINDS,
838
+ `kind must be one of: ${[...ATTACH_LINK_KINDS].join(", ")}`
829
839
  );
830
840
  if ("error" in normalized) return failure(normalized.error);
831
841
  const { kind, externalId } = normalized;
@@ -1000,7 +1010,7 @@ function seedVerifiedLink(identityId, params) {
1000
1010
  const normalized = normalizeLinkInput(
1001
1011
  params.kind,
1002
1012
  params.externalId,
1003
- LINK_KINDS,
1013
+ TRUSTED_LINK_KINDS,
1004
1014
  "unknown identity link kind"
1005
1015
  );
1006
1016
  if ("error" in normalized) throw new Error(normalized.error);
package/dist/setup.js CHANGED
@@ -609,19 +609,20 @@ async function handleEmailSend(request) {
609
609
 
610
610
  // src/simulator/identities.ts
611
611
  var import_node_crypto3 = __toESM(require("crypto"));
612
- var LINK_KINDS = /* @__PURE__ */ new Set([
613
- "line",
614
- "facebook",
615
- "instagram",
616
- "email",
617
- "phone",
618
- "project_auth_user",
619
- "dashboard_user"
620
- ]);
612
+ var ATTACH_LINK_KINDS = /* @__PURE__ */ new Set(["line", "facebook", "instagram", "email", "phone"]);
621
613
  var RESOLVE_KINDS = /* @__PURE__ */ new Set(["phone", "email", "line"]);
622
614
  var E164_PHONE = /^\+[1-9]\d{1,14}$/;
623
615
  var SEARCH_DEFAULT_LIMIT = 50;
624
616
  var SEARCH_MAX_LIMIT = 100;
617
+ function asciiLowercaseTrim(value) {
618
+ const trimmed = value.trim();
619
+ let out = "";
620
+ for (let i = 0; i < trimmed.length; i++) {
621
+ const code = trimmed.charCodeAt(i);
622
+ out += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : trimmed[i];
623
+ }
624
+ return out;
625
+ }
625
626
  var IdentityGraphError = class extends Error {
626
627
  };
627
628
  function now() {
@@ -631,12 +632,12 @@ function linksFor(identityId) {
631
632
  return state.identityLinks.filter((l) => l.identityId === identityId);
632
633
  }
633
634
  function comparableExternalId(kind, externalId) {
634
- if (kind === "email") return externalId.trim().toLowerCase();
635
+ if (kind === "email") return asciiLowercaseTrim(externalId);
635
636
  return externalId;
636
637
  }
637
638
  function normalizeExternalId(kind, externalId) {
638
639
  if (kind === "email") {
639
- const normalized = externalId.trim().toLowerCase();
640
+ const normalized = asciiLowercaseTrim(externalId);
640
641
  return normalized.length > 0 ? { externalId: normalized } : { error: "externalId is required" };
641
642
  }
642
643
  if (kind === "phone" && !E164_PHONE.test(externalId)) {
@@ -797,8 +798,8 @@ async function handleAttachLink(identityId, request) {
797
798
  const normalized = normalizeLinkInput(
798
799
  body.kind,
799
800
  body.externalId,
800
- LINK_KINDS,
801
- `kind must be one of: ${[...LINK_KINDS].join(", ")}`
801
+ ATTACH_LINK_KINDS,
802
+ `kind must be one of: ${[...ATTACH_LINK_KINDS].join(", ")}`
802
803
  );
803
804
  if ("error" in normalized) return failure(normalized.error);
804
805
  const { kind, externalId } = normalized;
package/dist/setup.mjs CHANGED
@@ -585,19 +585,20 @@ async function handleEmailSend(request) {
585
585
 
586
586
  // src/simulator/identities.ts
587
587
  import crypto3 from "crypto";
588
- var LINK_KINDS = /* @__PURE__ */ new Set([
589
- "line",
590
- "facebook",
591
- "instagram",
592
- "email",
593
- "phone",
594
- "project_auth_user",
595
- "dashboard_user"
596
- ]);
588
+ var ATTACH_LINK_KINDS = /* @__PURE__ */ new Set(["line", "facebook", "instagram", "email", "phone"]);
597
589
  var RESOLVE_KINDS = /* @__PURE__ */ new Set(["phone", "email", "line"]);
598
590
  var E164_PHONE = /^\+[1-9]\d{1,14}$/;
599
591
  var SEARCH_DEFAULT_LIMIT = 50;
600
592
  var SEARCH_MAX_LIMIT = 100;
593
+ function asciiLowercaseTrim(value) {
594
+ const trimmed = value.trim();
595
+ let out = "";
596
+ for (let i = 0; i < trimmed.length; i++) {
597
+ const code = trimmed.charCodeAt(i);
598
+ out += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : trimmed[i];
599
+ }
600
+ return out;
601
+ }
601
602
  var IdentityGraphError = class extends Error {
602
603
  };
603
604
  function now() {
@@ -607,12 +608,12 @@ function linksFor(identityId) {
607
608
  return state.identityLinks.filter((l) => l.identityId === identityId);
608
609
  }
609
610
  function comparableExternalId(kind, externalId) {
610
- if (kind === "email") return externalId.trim().toLowerCase();
611
+ if (kind === "email") return asciiLowercaseTrim(externalId);
611
612
  return externalId;
612
613
  }
613
614
  function normalizeExternalId(kind, externalId) {
614
615
  if (kind === "email") {
615
- const normalized = externalId.trim().toLowerCase();
616
+ const normalized = asciiLowercaseTrim(externalId);
616
617
  return normalized.length > 0 ? { externalId: normalized } : { error: "externalId is required" };
617
618
  }
618
619
  if (kind === "phone" && !E164_PHONE.test(externalId)) {
@@ -773,8 +774,8 @@ async function handleAttachLink(identityId, request) {
773
774
  const normalized = normalizeLinkInput(
774
775
  body.kind,
775
776
  body.externalId,
776
- LINK_KINDS,
777
- `kind must be one of: ${[...LINK_KINDS].join(", ")}`
777
+ ATTACH_LINK_KINDS,
778
+ `kind must be one of: ${[...ATTACH_LINK_KINDS].join(", ")}`
778
779
  );
779
780
  if ("error" in normalized) return failure(normalized.error);
780
781
  const { kind, externalId } = normalized;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stardeck-customer-apps/testing",
3
- "version": "0.6.0",
3
+ "version": "0.6.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",