@sixb/core 0.1.13 → 0.1.14

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.
Files changed (97) hide show
  1. package/dist/actions/index.js +9 -9
  2. package/dist/agents/index.js +16 -16
  3. package/dist/auth/errors.d.ts +12 -0
  4. package/dist/auth/errors.d.ts.map +1 -1
  5. package/dist/auth/index.d.ts +1 -1
  6. package/dist/auth/index.d.ts.map +1 -1
  7. package/dist/auth/index.js +5 -3
  8. package/dist/auth/index.js.map +1 -1
  9. package/dist/auth/runtime.d.ts.map +1 -1
  10. package/dist/auth/strategy.d.ts +2 -0
  11. package/dist/auth/strategy.d.ts.map +1 -1
  12. package/dist/auth/strategy.js +4 -2
  13. package/dist/auth/strategy.js.map +1 -1
  14. package/dist/auth/types.d.ts +8 -0
  15. package/dist/auth/types.d.ts.map +1 -1
  16. package/dist/bootstrap/index.js +20 -20
  17. package/dist/{chunk-rqtdtm43.js → chunk-00pfcqh4.js} +1 -1
  18. package/dist/{chunk-cvrbhvtr.js → chunk-16jenmzw.js} +10 -10
  19. package/dist/{chunk-0321g649.js → chunk-2jntasmh.js} +13 -2
  20. package/dist/{chunk-0321g649.js.map → chunk-2jntasmh.js.map} +3 -3
  21. package/dist/{chunk-n33e8dz8.js → chunk-3a338wrp.js} +1 -1
  22. package/dist/{chunk-gc226ten.js → chunk-3fpgxpsq.js} +3 -3
  23. package/dist/{chunk-gmt22nxx.js → chunk-4ypbe95r.js} +1 -1
  24. package/dist/{chunk-9pfw47qx.js → chunk-6rzb1g6h.js} +52 -47
  25. package/dist/{chunk-9pfw47qx.js.map → chunk-6rzb1g6h.js.map} +7 -7
  26. package/dist/{chunk-898y24dd.js → chunk-728fp090.js} +1 -1
  27. package/dist/{chunk-693f3zn8.js → chunk-dv4ct8mp.js} +2 -2
  28. package/dist/{chunk-jhyc777j.js → chunk-e2c5yxfe.js} +1 -1
  29. package/dist/{chunk-darm7eeg.js → chunk-gct3m1da.js} +1 -1
  30. package/dist/{chunk-mf6hwpzh.js → chunk-hj0n3c2p.js} +12 -12
  31. package/dist/{chunk-91wthfwe.js → chunk-hxgj4kzd.js} +4 -4
  32. package/dist/{chunk-w9bp61e7.js → chunk-jfdggg1p.js} +1 -1
  33. package/dist/{chunk-04h4t2b5.js → chunk-kxea54yg.js} +1 -1
  34. package/dist/{chunk-jmwy25mf.js → chunk-ma1mhh7w.js} +5 -5
  35. package/dist/{chunk-63fp9x3q.js → chunk-pvgpckm1.js} +2 -2
  36. package/dist/{chunk-a69fkrtr.js → chunk-q2xghyft.js} +1 -1
  37. package/dist/{chunk-s24qbp32.js → chunk-wn7mznxc.js} +2 -2
  38. package/dist/{chunk-gbcrz0gr.js → chunk-wnxabtn4.js} +2 -2
  39. package/dist/{chunk-bep5rrdq.js → chunk-ww185kt6.js} +1 -1
  40. package/dist/{chunk-2hbhn1ff.js → chunk-yvf2jqj8.js} +1 -1
  41. package/dist/execution/agent.js +16 -16
  42. package/dist/execution/primitive.js +16 -16
  43. package/dist/execution/request.js +16 -16
  44. package/dist/index.js +22 -22
  45. package/dist/materializer/index.js +6 -6
  46. package/dist/models/execution/index.js +6 -6
  47. package/dist/objects/index.js +9 -9
  48. package/dist/objects/query/index.js +6 -6
  49. package/dist/pipelines/index.js +7 -7
  50. package/dist/projections/internal.js +5 -5
  51. package/dist/runtime/internal.js +8 -8
  52. package/dist/shares/internal.js +6 -6
  53. package/dist/storage/auth/errors.d.ts +1 -1
  54. package/dist/storage/auth/errors.d.ts.map +1 -1
  55. package/dist/storage/auth/in-memory/auth-storage.d.ts +2 -1
  56. package/dist/storage/auth/in-memory/auth-storage.d.ts.map +1 -1
  57. package/dist/storage/auth/types.d.ts +15 -7
  58. package/dist/storage/auth/types.d.ts.map +1 -1
  59. package/dist/storage/file-upload-sessions/provider.js +3 -3
  60. package/dist/storage/index.js +5 -5
  61. package/dist/storage/workflow-runs/provider.js +3 -3
  62. package/dist/syncs/index.js +7 -7
  63. package/dist/testing/auth-storage-contract.d.ts.map +1 -1
  64. package/dist/testing/index.js +107 -139
  65. package/dist/testing/index.js.map +3 -3
  66. package/dist/webhooks/internal.js +5 -5
  67. package/dist/workflows/index.js +17 -17
  68. package/package.json +1 -1
  69. package/src/auth/errors.ts +23 -0
  70. package/src/auth/index.ts +1 -1
  71. package/src/auth/runtime.ts +56 -22
  72. package/src/auth/strategy.ts +2 -0
  73. package/src/auth/types.ts +8 -0
  74. package/src/storage/auth/errors.ts +0 -1
  75. package/src/storage/auth/in-memory/auth-storage.ts +44 -65
  76. package/src/storage/auth/types.ts +15 -7
  77. package/src/testing/auth-storage-contract.ts +104 -130
  78. /package/dist/{chunk-rqtdtm43.js.map → chunk-00pfcqh4.js.map} +0 -0
  79. /package/dist/{chunk-cvrbhvtr.js.map → chunk-16jenmzw.js.map} +0 -0
  80. /package/dist/{chunk-n33e8dz8.js.map → chunk-3a338wrp.js.map} +0 -0
  81. /package/dist/{chunk-gc226ten.js.map → chunk-3fpgxpsq.js.map} +0 -0
  82. /package/dist/{chunk-gmt22nxx.js.map → chunk-4ypbe95r.js.map} +0 -0
  83. /package/dist/{chunk-898y24dd.js.map → chunk-728fp090.js.map} +0 -0
  84. /package/dist/{chunk-693f3zn8.js.map → chunk-dv4ct8mp.js.map} +0 -0
  85. /package/dist/{chunk-jhyc777j.js.map → chunk-e2c5yxfe.js.map} +0 -0
  86. /package/dist/{chunk-darm7eeg.js.map → chunk-gct3m1da.js.map} +0 -0
  87. /package/dist/{chunk-mf6hwpzh.js.map → chunk-hj0n3c2p.js.map} +0 -0
  88. /package/dist/{chunk-91wthfwe.js.map → chunk-hxgj4kzd.js.map} +0 -0
  89. /package/dist/{chunk-w9bp61e7.js.map → chunk-jfdggg1p.js.map} +0 -0
  90. /package/dist/{chunk-04h4t2b5.js.map → chunk-kxea54yg.js.map} +0 -0
  91. /package/dist/{chunk-jmwy25mf.js.map → chunk-ma1mhh7w.js.map} +0 -0
  92. /package/dist/{chunk-63fp9x3q.js.map → chunk-pvgpckm1.js.map} +0 -0
  93. /package/dist/{chunk-a69fkrtr.js.map → chunk-q2xghyft.js.map} +0 -0
  94. /package/dist/{chunk-s24qbp32.js.map → chunk-wn7mznxc.js.map} +0 -0
  95. /package/dist/{chunk-gbcrz0gr.js.map → chunk-wnxabtn4.js.map} +0 -0
  96. /package/dist/{chunk-bep5rrdq.js.map → chunk-ww185kt6.js.map} +0 -0
  97. /package/dist/{chunk-2hbhn1ff.js.map → chunk-yvf2jqj8.js.map} +0 -0
@@ -81,6 +81,34 @@ async function createUser(
81
81
  })
82
82
  }
83
83
 
84
+ async function completeOidcSignInForAva(
85
+ storage: AuthStorage,
86
+ directoryGroupIds: readonly string[] | undefined
87
+ ): Promise<void> {
88
+ await storage.oidcAuthorizationAttempts.create({
89
+ id: "oidc_directory",
90
+ projectId,
91
+ strategyId: "entra",
92
+ audience: "atlas",
93
+ stateHash: "directory-state",
94
+ nonceHash: "nonce-hash",
95
+ codeVerifier: "verifier",
96
+ createdAt: at("2026-05-14T10:00:00.000Z"),
97
+ expiresAt: at("2026-05-14T10:10:00.000Z"),
98
+ })
99
+ await storage.completeOidcSignIn({
100
+ projectId,
101
+ oidcAuthorizationAttemptId: "oidc_directory",
102
+ stateHash: "directory-state",
103
+ completedAt: at("2026-05-14T10:01:00.000Z"),
104
+ subject: "entra-ava",
105
+ email: "ava@acme.com",
106
+ directoryGroupIds,
107
+ newUserId: "usr_unused",
108
+ session: sessionInput("ses_directory"),
109
+ })
110
+ }
111
+
84
112
  /**
85
113
  * Runs the shared `AuthStorage` contract against any storage implementation.
86
114
  *
@@ -1721,91 +1749,6 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
1721
1749
  })
1722
1750
  })
1723
1751
 
1724
- test("closes bootstrap user creation when an active user already exists", async () => {
1725
- await withStorage(async (storage) => {
1726
- await createUser(storage, {
1727
- id: "usr_existing",
1728
- email: "existing@acme.com",
1729
- })
1730
- await storage.magicLinks.create({
1731
- id: "ml_1",
1732
- projectId,
1733
- strategyId: "magic-link",
1734
- audience: "atlas",
1735
- email: "founder@acme.com",
1736
- tokenHash: "link-hash",
1737
- createdAt: at("2026-05-14T10:01:00.000Z"),
1738
- expiresAt: at("2026-05-14T10:16:00.000Z"),
1739
- })
1740
-
1741
- await expectAuthError(
1742
- storage.completeMagicLinkSignIn({
1743
- projectId,
1744
- magicLinkId: "ml_1",
1745
- tokenHash: "link-hash",
1746
- completedAt: at("2026-05-14T10:03:00.000Z"),
1747
- newUserId: "usr_founder",
1748
- allowUserCreationWithoutInvitation: true,
1749
- requireNoActiveUsersForUserCreation: true,
1750
- session: sessionInput("ses_founder"),
1751
- }),
1752
- "user_creation_not_allowed"
1753
- )
1754
- await expect(
1755
- storage.users.getByEmail({ projectId, email: "founder@acme.com" })
1756
- ).resolves.toBeNull()
1757
- await expect(storage.magicLinks.getById({ projectId, id: "ml_1" })).resolves.toMatchObject({
1758
- consumedAt: at("2026-05-14T10:03:00.000Z"),
1759
- })
1760
- })
1761
- })
1762
-
1763
- test("does not apply the bootstrap closure guard to invited user creation", async () => {
1764
- await withStorage(async (storage) => {
1765
- await createUser(storage, {
1766
- id: "usr_existing",
1767
- email: "existing@acme.com",
1768
- })
1769
- await storage.invitations.createOrUpdateActive({
1770
- id: "inv_1",
1771
- projectId,
1772
- email: "invited@acme.com",
1773
- groupIds: ["commercial"],
1774
- createdAt: at("2026-05-14T10:00:00.000Z"),
1775
- expiresAt: at("2026-05-21T10:00:00.000Z"),
1776
- })
1777
- await storage.magicLinks.create({
1778
- id: "ml_1",
1779
- projectId,
1780
- strategyId: "magic-link",
1781
- audience: "atlas",
1782
- email: "invited@acme.com",
1783
- tokenHash: "link-hash",
1784
- createdAt: at("2026-05-14T10:01:00.000Z"),
1785
- expiresAt: at("2026-05-14T10:16:00.000Z"),
1786
- })
1787
-
1788
- const result = await storage.completeMagicLinkSignIn({
1789
- projectId,
1790
- magicLinkId: "ml_1",
1791
- tokenHash: "link-hash",
1792
- completedAt: at("2026-05-14T10:03:00.000Z"),
1793
- newUserId: "usr_invited",
1794
- requireNoActiveUsersForUserCreation: true,
1795
- session: sessionInput("ses_invited"),
1796
- })
1797
-
1798
- expect(result.user).toMatchObject({
1799
- id: "usr_invited",
1800
- email: "invited@acme.com",
1801
- })
1802
- expect(result.invitation).toMatchObject({
1803
- id: "inv_1",
1804
- status: "accepted",
1805
- })
1806
- })
1807
- })
1808
-
1809
1752
  test("consumes valid magic links when an existing user is suspended", async () => {
1810
1753
  await withStorage(async (storage) => {
1811
1754
  await createUser(storage, { status: "suspended" })
@@ -1867,7 +1810,6 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
1867
1810
  completedAt: at("2026-05-14T10:02:00.000Z"),
1868
1811
  subject: "00u1",
1869
1812
  email: "renamed@acme.com",
1870
- emailVerified: true,
1871
1813
  claims: { email: "renamed@acme.com" },
1872
1814
  newUserId: "usr_unused",
1873
1815
  session: sessionInput("ses_oidc"),
@@ -1885,65 +1827,35 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
1885
1827
  })
1886
1828
  })
1887
1829
 
1888
- test("auto-links OIDC by verified email only when explicitly allowed", async () => {
1830
+ test("links a new OIDC identity to the existing user with its email", async () => {
1889
1831
  await withStorage(async (storage) => {
1890
1832
  await createUser(storage, { id: "usr_existing", email: "ava@acme.com" })
1891
1833
  await storage.oidcAuthorizationAttempts.create({
1892
- id: "oidc_blocked",
1834
+ id: "oidc_1",
1893
1835
  projectId,
1894
1836
  strategyId: "okta",
1895
1837
  audience: "atlas",
1896
- stateHash: "blocked-state",
1838
+ stateHash: "state-hash",
1897
1839
  nonceHash: "nonce-hash",
1898
1840
  codeVerifier: "verifier",
1899
1841
  createdAt: at("2026-05-14T10:00:00.000Z"),
1900
1842
  expiresAt: at("2026-05-14T10:10:00.000Z"),
1901
1843
  })
1902
1844
 
1903
- await expectAuthError(
1904
- storage.completeOidcSignIn({
1905
- projectId,
1906
- oidcAuthorizationAttemptId: "oidc_blocked",
1907
- stateHash: "blocked-state",
1908
- completedAt: at("2026-05-14T10:01:00.000Z"),
1909
- subject: "00u1",
1910
- email: "ava@acme.com",
1911
- emailVerified: false,
1912
- autoLinkByVerifiedEmail: true,
1913
- newUserId: "usr_unused",
1914
- session: sessionInput("ses_blocked"),
1915
- }),
1916
- "email_link_not_allowed"
1917
- )
1918
-
1919
- await storage.oidcAuthorizationAttempts.create({
1920
- id: "oidc_allowed",
1921
- projectId,
1922
- strategyId: "okta",
1923
- audience: "atlas",
1924
- stateHash: "allowed-state",
1925
- nonceHash: "nonce-hash",
1926
- codeVerifier: "verifier",
1927
- createdAt: at("2026-05-14T10:02:00.000Z"),
1928
- expiresAt: at("2026-05-14T10:12:00.000Z"),
1929
- })
1930
1845
  const result = await storage.completeOidcSignIn({
1931
1846
  projectId,
1932
- oidcAuthorizationAttemptId: "oidc_allowed",
1933
- stateHash: "allowed-state",
1934
- completedAt: at("2026-05-14T10:03:00.000Z"),
1847
+ oidcAuthorizationAttemptId: "oidc_1",
1848
+ stateHash: "state-hash",
1849
+ completedAt: at("2026-05-14T10:01:00.000Z"),
1935
1850
  subject: "00u1",
1936
1851
  email: "ava@acme.com",
1937
- emailVerified: true,
1938
- autoLinkByVerifiedEmail: true,
1939
1852
  newUserId: "usr_unused",
1940
- session: sessionInput("ses_allowed"),
1853
+ session: sessionInput("ses_oidc"),
1941
1854
  })
1942
1855
 
1943
1856
  expect(result.user.id).toBe("usr_existing")
1944
- expect(result.identity).toMatchObject({
1945
- userId: "usr_existing",
1946
- })
1857
+ expect(result.identity).toMatchObject({ subject: "00u1", userId: "usr_existing" })
1858
+ await expect(storage.users.getById({ projectId, id: "usr_unused" })).resolves.toBeNull()
1947
1859
  })
1948
1860
  })
1949
1861
 
@@ -1977,7 +1889,6 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
1977
1889
  subject: "00u1",
1978
1890
  email: "ava@acme.com",
1979
1891
  displayName: "Ava Chen",
1980
- emailVerified: true,
1981
1892
  newUserId: "usr_oidc",
1982
1893
  session: sessionInput("ses_oidc"),
1983
1894
  })
@@ -2024,7 +1935,6 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
2024
1935
  completedAt: at("2026-05-14T10:01:00.000Z"),
2025
1936
  subject: "00u1",
2026
1937
  email: "ava@acme.com",
2027
- emailVerified: true,
2028
1938
  newUserId: "usr_oidc",
2029
1939
  session: sessionInput("ses_oidc"),
2030
1940
  }),
@@ -2036,7 +1946,7 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
2036
1946
  })
2037
1947
  })
2038
1948
 
2039
- test("allows first OIDC bootstrap user creation with manual groups", async () => {
1949
+ test("allows OIDC bootstrap user creation with manual groups", async () => {
2040
1950
  await withStorage(async (storage) => {
2041
1951
  await storage.oidcAuthorizationAttempts.create({
2042
1952
  id: "oidc_bootstrap",
@@ -2057,9 +1967,7 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
2057
1967
  completedAt: at("2026-05-14T10:01:00.000Z"),
2058
1968
  subject: "00u1",
2059
1969
  email: "founder@acme.com",
2060
- emailVerified: true,
2061
1970
  allowUserCreationWithoutInvitation: true,
2062
- requireNoActiveUsersForUserCreation: true,
2063
1971
  manualGroupIds: ["security-admins"],
2064
1972
  newUserId: "usr_founder",
2065
1973
  session: sessionInput("ses_oidc_bootstrap"),
@@ -2075,6 +1983,72 @@ export function runAuthStorageContractSuite<TStorage extends AuthStorage>(
2075
1983
  })
2076
1984
  })
2077
1985
 
1986
+ test("syncs directory memberships to exactly the groups the provider grants", async () => {
1987
+ await withStorage(async (storage) => {
1988
+ await createUser(storage)
1989
+ for (const [groupId, source] of [
1990
+ ["security-admins", "manual"],
1991
+ ["commercial", "invitation"],
1992
+ ["legacy-team", "directory"],
1993
+ ] as const) {
1994
+ await storage.groupMemberships.upsert({ projectId, userId: "usr_1", groupId, source })
1995
+ }
1996
+
1997
+ await completeOidcSignInForAva(storage, ["security-admins", "field-ops"])
1998
+
1999
+ // legacy-team is no longer granted; security-admins keeps its manual source.
2000
+ await expect(
2001
+ storage.groupMemberships.listForUser({ projectId, userId: "usr_1" })
2002
+ ).resolves.toMatchObject([
2003
+ { groupId: "commercial", source: "invitation" },
2004
+ { groupId: "field-ops", source: "directory" },
2005
+ { groupId: "security-admins", source: "manual" },
2006
+ ])
2007
+ })
2008
+ })
2009
+
2010
+ test("removes every directory membership when the provider grants no groups", async () => {
2011
+ await withStorage(async (storage) => {
2012
+ await createUser(storage)
2013
+ await storage.groupMemberships.upsert({
2014
+ projectId,
2015
+ userId: "usr_1",
2016
+ groupId: "security-admins",
2017
+ source: "manual",
2018
+ })
2019
+ await storage.groupMemberships.upsert({
2020
+ projectId,
2021
+ userId: "usr_1",
2022
+ groupId: "field-ops",
2023
+ source: "directory",
2024
+ })
2025
+
2026
+ await completeOidcSignInForAva(storage, [])
2027
+
2028
+ await expect(
2029
+ storage.groupMemberships.listForUser({ projectId, userId: "usr_1" })
2030
+ ).resolves.toMatchObject([{ groupId: "security-admins", source: "manual" }])
2031
+ })
2032
+ })
2033
+
2034
+ test("leaves directory memberships alone when sign-in syncs no groups", async () => {
2035
+ await withStorage(async (storage) => {
2036
+ await createUser(storage)
2037
+ await storage.groupMemberships.upsert({
2038
+ projectId,
2039
+ userId: "usr_1",
2040
+ groupId: "field-ops",
2041
+ source: "directory",
2042
+ })
2043
+
2044
+ await completeOidcSignInForAva(storage, undefined)
2045
+
2046
+ await expect(
2047
+ storage.groupMemberships.listForUser({ projectId, userId: "usr_1" })
2048
+ ).resolves.toMatchObject([{ groupId: "field-ops", source: "directory" }])
2049
+ })
2050
+ })
2051
+
2078
2052
  test("suspends users and revokes active sessions immediately", async () => {
2079
2053
  await withStorage(async (storage) => {
2080
2054
  await createUser(storage)