@baseworks/iam 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -17,21 +17,10 @@ function buildIamCommand(deps) {
17
17
  ["id", user.id]
18
18
  ]);
19
19
  });
20
- const users = iam.command("users").description("user directory");
21
- users.command("find <email>").description("resolve a user id by exact email (for invites)").action(async (email) => {
22
- const { user } = await http.get(
23
- `/users/lookup?email=${encodeURIComponent(email)}`
24
- ).catch(die);
25
- kv([
26
- ["id", user.id],
27
- ["email", user.email],
28
- ["name", user.name ?? "\u2014"]
29
- ]);
30
- });
31
20
  const token = iam.command("token").description("api tokens (service / cli / agent credentials)");
32
21
  outputOpt(token.command("list")).description("active tokens you can see").action(async (opts) => {
33
22
  const { tokens } = await http.get(
34
- "/v1/tokens"
23
+ "/tokens"
35
24
  ).catch(die);
36
25
  printOutput(
37
26
  tokens,
@@ -45,7 +34,7 @@ function buildIamCommand(deps) {
45
34
  );
46
35
  });
47
36
  token.command("issue <name>").description("issue a token; the secret is printed once").option("--type <type>", "user | service | cli | agent", "service").option("--org <id>", "bind to an organization (opaque context)").option("--scope <scope...>", "grant scopes").action(async (name, opts) => {
48
- const res = await http.post("/v1/tokens", {
37
+ const res = await http.post("/tokens", {
49
38
  name,
50
39
  type: opts.type,
51
40
  org_id: opts.org ?? null,
@@ -58,7 +47,7 @@ function buildIamCommand(deps) {
58
47
  ]);
59
48
  });
60
49
  token.command("revoke <id>").description("revoke a token by id").action(async (id) => {
61
- await http.del(`/v1/tokens/${encodeURIComponent(id)}`).catch(die);
50
+ await http.del(`/tokens/${encodeURIComponent(id)}`).catch(die);
62
51
  success(`token revoked: ${id}`);
63
52
  });
64
53
  return iam;
package/dist/events.d.ts CHANGED
@@ -25,17 +25,17 @@ declare const UserEvents: _baseworks_foldbase.EventCatalog<{
25
25
  picture: z.ZodNullable<z.ZodString>;
26
26
  at: z.ZodNumber;
27
27
  }, "strip", z.ZodTypeAny, {
28
- email: string;
29
28
  at: number;
30
29
  subject: string;
31
30
  issuer: string;
31
+ email: string;
32
32
  name: string | null;
33
33
  picture: string | null;
34
34
  }, {
35
- email: string;
36
35
  at: number;
37
36
  subject: string;
38
37
  issuer: string;
38
+ email: string;
39
39
  name: string | null;
40
40
  picture: string | null;
41
41
  }>;
@@ -45,13 +45,13 @@ declare const UserEvents: _baseworks_foldbase.EventCatalog<{
45
45
  picture: z.ZodNullable<z.ZodString>;
46
46
  at: z.ZodNumber;
47
47
  }, "strip", z.ZodTypeAny, {
48
- email: string;
49
48
  at: number;
49
+ email: string;
50
50
  name: string | null;
51
51
  picture: string | null;
52
52
  }, {
53
- email: string;
54
53
  at: number;
54
+ email: string;
55
55
  name: string | null;
56
56
  picture: string | null;
57
57
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baseworks/iam",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "IAM capability: identity (users) + credentials (api tokens). Typed HTTP client, foldbase event catalog, projections, and CLI plugin for iam-service. Contract-first, versioned with the service. Roles/PDP live in @baseworks/org.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -27,15 +27,12 @@ describe('flect iam whoami', () => {
27
27
  })
28
28
  })
29
29
 
30
- // ── users find ────────────────────────────────────────────────────────────────
30
+ // ── no users find ─────────────────────────────────────────────────────────────
31
31
 
32
- describe('flect iam users find', () => {
33
- it('resolves a user id by email', async () => {
34
- mocks.mockGet('/users/lookup', { user: USER })
32
+ describe('flect iam users', () => {
33
+ it('is gone: looking a person up by email is for services, not for a CLI', async () => {
35
34
  const r = await run(['iam', 'users', 'find', 'ali@acme.test'])
36
- expect(r.exitCode).toBe(0)
37
- expect(r.stdout).toContain(USER.id)
38
- expect(r.stdout).toContain('ali@acme.test')
35
+ expect(r.stdout + r.stderr).toMatch(/unknown command/)
39
36
  })
40
37
  })
41
38
 
@@ -43,7 +40,7 @@ describe('flect iam users find', () => {
43
40
 
44
41
  describe('flect iam token', () => {
45
42
  it('list renders NAME / TYPE / PREFIX columns', async () => {
46
- mocks.mockGet('/v1/tokens', {
43
+ mocks.mockGet('/tokens', {
47
44
  tokens: [{ id: 't1', name: 'ci', type: 'service', key_prefix: 'bwt_abc12345', expires_at: null }],
48
45
  })
49
46
  const r = await run(['iam', 'token', 'list'])
@@ -54,14 +51,14 @@ describe('flect iam token', () => {
54
51
  })
55
52
 
56
53
  it('issue prints the one-time secret', async () => {
57
- mocks.mockPost('/v1/tokens', { token: { id: 't1', key_prefix: 'bwt_secret1234' }, secret: 'bwt_secret1234_rest' })
54
+ mocks.mockPost('/tokens', { token: { id: 't1', key_prefix: 'bwt_secret1234' }, secret: 'bwt_secret1234_rest' })
58
55
  const r = await run(['iam', 'token', 'issue', 'ci', '--type', 'service'])
59
56
  expect(r.exitCode).toBe(0)
60
57
  expect(r.stdout).toContain('bwt_secret1234_rest')
61
58
  })
62
59
 
63
60
  it('revoke calls DELETE and reports success', async () => {
64
- mocks.mockDelete('/v1/tokens/t1')
61
+ mocks.mockDelete('/tokens/t1')
65
62
  const r = await run(['iam', 'token', 'revoke', 't1'])
66
63
  expect(r.exitCode).toBe(0)
67
64
  expect(r.stdout).toContain('t1')
package/src/cli.ts CHANGED
@@ -41,24 +41,11 @@ export function buildIamCommand(deps: IamCliDeps): Command {
41
41
  ])
42
42
  })
43
43
 
44
- // ── users ─────────────────────────────────────────────────────────────────--
45
- const users = iam.command('users').description('user directory')
46
-
47
- users
48
- .command('find <email>')
49
- .description('resolve a user id by exact email (for invites)')
50
- .action(async (email: string) => {
51
- const { user } = await http
52
- .get<{ user: { id: string; email: string; name: string | null } }>(
53
- `/users/lookup?email=${encodeURIComponent(email)}`,
54
- )
55
- .catch(die)
56
- kv([
57
- ['id', user.id],
58
- ['email', user.email],
59
- ['name', user.name ?? '—'],
60
- ])
61
- })
44
+ // There is no `users find <email>`. It asked iam "does this address have an
45
+ // account here?" with a person's token, which is an account-existence oracle;
46
+ // iam answers that to services only now. Invite by email instead
47
+ // (`org invite <email>`): the invitation reaches the person without anyone
48
+ // learning their user id first.
62
49
 
63
50
  // ── token (credentials) ───────────────────────────────────────────────────--
64
51
  const token = iam.command('token').description('api tokens (service / cli / agent credentials)')
@@ -68,7 +55,7 @@ export function buildIamCommand(deps: IamCliDeps): Command {
68
55
  .action(async (opts: { output?: string }) => {
69
56
  const { tokens } = await http
70
57
  .get<{ tokens: Array<{ id: string; name: string; type: string; key_prefix: string; expires_at: number | null }> }>(
71
- '/v1/tokens',
58
+ '/tokens',
72
59
  )
73
60
  .catch(die)
74
61
  printOutput(tokens as unknown as Record<string, unknown>[], opts.output, () =>
@@ -89,7 +76,7 @@ export function buildIamCommand(deps: IamCliDeps): Command {
89
76
  .option('--scope <scope...>', 'grant scopes')
90
77
  .action(async (name: string, opts: { type?: string; org?: string; scope?: string[] }) => {
91
78
  const res = await http
92
- .post<{ token: { id: string; key_prefix: string }; secret: string }>('/v1/tokens', {
79
+ .post<{ token: { id: string; key_prefix: string }; secret: string }>('/tokens', {
93
80
  name,
94
81
  type: opts.type,
95
82
  org_id: opts.org ?? null,
@@ -107,7 +94,7 @@ export function buildIamCommand(deps: IamCliDeps): Command {
107
94
  .command('revoke <id>')
108
95
  .description('revoke a token by id')
109
96
  .action(async (id: string) => {
110
- await http.del(`/v1/tokens/${encodeURIComponent(id)}`).catch(die)
97
+ await http.del(`/tokens/${encodeURIComponent(id)}`).catch(die)
111
98
  success(`token revoked: ${id}`)
112
99
  })
113
100