@minion-stack/db 0.2.0 → 0.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.
Files changed (57) hide show
  1. package/dist/pg/crypto.d.ts +8 -0
  2. package/dist/pg/crypto.d.ts.map +1 -0
  3. package/dist/pg/crypto.js +42 -0
  4. package/dist/pg/crypto.js.map +1 -0
  5. package/dist/pg/crypto.test.d.ts +2 -0
  6. package/dist/pg/crypto.test.d.ts.map +1 -0
  7. package/dist/pg/crypto.test.js +25 -0
  8. package/dist/pg/crypto.test.js.map +1 -0
  9. package/dist/pg/identity-mapper.d.ts +36 -0
  10. package/dist/pg/identity-mapper.d.ts.map +1 -0
  11. package/dist/pg/identity-mapper.js +18 -0
  12. package/dist/pg/identity-mapper.js.map +1 -0
  13. package/dist/pg/identity-mapper.test.d.ts +2 -0
  14. package/dist/pg/identity-mapper.test.d.ts.map +1 -0
  15. package/dist/pg/identity-mapper.test.js +32 -0
  16. package/dist/pg/identity-mapper.test.js.map +1 -0
  17. package/dist/pg/schema/index.d.ts +6 -0
  18. package/dist/pg/schema/index.d.ts.map +1 -0
  19. package/dist/pg/schema/index.js +6 -0
  20. package/dist/pg/schema/index.js.map +1 -0
  21. package/dist/pg/schema/profiles.d.ts +134 -0
  22. package/dist/pg/schema/profiles.d.ts.map +1 -0
  23. package/dist/pg/schema/profiles.js +20 -0
  24. package/dist/pg/schema/profiles.js.map +1 -0
  25. package/dist/pg/schema/user-identities.d.ts +237 -0
  26. package/dist/pg/schema/user-identities.d.ts.map +1 -0
  27. package/dist/pg/schema/user-identities.js +31 -0
  28. package/dist/pg/schema/user-identities.js.map +1 -0
  29. package/dist/schema/index.d.ts +3 -0
  30. package/dist/schema/index.d.ts.map +1 -1
  31. package/dist/schema/index.js +2 -0
  32. package/dist/schema/index.js.map +1 -1
  33. package/dist/schema/personal-agents.d.ts +1 -1
  34. package/dist/schema/reliability-events.d.ts +1 -1
  35. package/dist/schema/server-provision-configs.d.ts +1 -1
  36. package/dist/schema/session-tasks.d.ts +1 -1
  37. package/dist/schema/skill-execution-stats.d.ts +1 -1
  38. package/dist/schema/tasks.d.ts +1 -1
  39. package/dist/schema/user-identities.d.ts +254 -0
  40. package/dist/schema/user-identities.d.ts.map +1 -0
  41. package/dist/schema/user-identities.js +30 -0
  42. package/dist/schema/user-identities.js.map +1 -0
  43. package/dist/schema/workspace-membership.d.ts +94 -0
  44. package/dist/schema/workspace-membership.d.ts.map +1 -0
  45. package/dist/schema/workspace-membership.js +24 -0
  46. package/dist/schema/workspace-membership.js.map +1 -0
  47. package/package.json +18 -9
  48. package/src/pg/crypto.test.ts +28 -0
  49. package/src/pg/crypto.ts +44 -0
  50. package/src/pg/identity-mapper.test.ts +35 -0
  51. package/src/pg/identity-mapper.ts +48 -0
  52. package/src/pg/schema/index.ts +12 -0
  53. package/src/pg/schema/profiles.ts +20 -0
  54. package/src/pg/schema/user-identities.ts +35 -0
  55. package/src/schema/index.ts +3 -0
  56. package/src/schema/user-identities.ts +34 -0
  57. package/src/schema/workspace-membership.ts +31 -0
@@ -0,0 +1,31 @@
1
+ import { pgTable, uuid, text, timestamp, bigint, uniqueIndex, index } from 'drizzle-orm/pg-core';
2
+ import { profiles } from './profiles.js';
3
+ /**
4
+ * Canonical per-user identity row linking a user to BOTH OAuth providers
5
+ * (kind='oauth', e.g. google) AND channel identities (kind='channel',
6
+ * e.g. whatsapp/telegram/discord/signal/slack). This is the single link
7
+ * table replacing the SQLite channel_identities + the oauth side of account.
8
+ * Secret material (OAuth refresh-token ADC blob) is app-level AES-256-GCM
9
+ * sealed into secretCiphertext/secretIv; null for channel identities.
10
+ */
11
+ export const userIdentities = pgTable('user_identities', {
12
+ id: uuid('id').primaryKey().defaultRandom(),
13
+ userId: uuid('user_id')
14
+ .notNull()
15
+ .references(() => profiles.id, { onDelete: 'cascade' }),
16
+ provider: text('provider').notNull(), // 'google'|'whatsapp'|'telegram'|'discord'|'signal'|'slack'
17
+ kind: text('kind', { enum: ['oauth', 'channel'] }).notNull(),
18
+ externalId: text('external_id').notNull(),
19
+ displayName: text('display_name'),
20
+ scope: text('scope'),
21
+ secretCiphertext: text('secret_ciphertext'),
22
+ secretIv: text('secret_iv'),
23
+ expiresAt: bigint('expires_at', { mode: 'number' }),
24
+ verifiedAt: bigint('verified_at', { mode: 'number' }),
25
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
26
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
27
+ }, (t) => [
28
+ uniqueIndex('idx_user_identity_unique').on(t.provider, t.externalId),
29
+ index('idx_user_identity_user').on(t.userId),
30
+ ]);
31
+ //# sourceMappingURL=user-identities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-identities.js","sourceRoot":"","sources":["../../../src/pg/schema/user-identities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CACnC,iBAAiB,EACjB;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC,aAAa,EAAE;IAC3C,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACzD,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,4DAA4D;IAClG,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE;IAC5D,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC;IACjC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;IACpB,gBAAgB,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAC3C,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACnD,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACrD,SAAS,EAAE,SAAS,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;IACjF,SAAS,EAAE,SAAS,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;CAClF,EACD,CAAC,CAAC,EAAE,EAAE,CAAC;IACL,WAAW,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC;IACpE,KAAK,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;CAC7C,CACF,CAAC"}
@@ -31,7 +31,10 @@ export { serverBackups } from './server-backups.js';
31
31
  export { agentGroups, agentGroupMembers } from './agent-groups.js';
32
32
  export { unifiedEvents } from './unified-events.js';
33
33
  export { channelIdentities } from './channel-identities.js';
34
+ export { userIdentities } from './user-identities.js';
34
35
  export { personalAgents } from './personal-agents.js';
35
36
  export { builtSkills, builtSkillTools, builtChapters, builtChapterEdges, builtChapterTools, builtAgents, builtAgentSkills, builtTools, agentBuiltSkills, } from './builder.js';
36
37
  export { userPreferences } from './user-preferences.js';
38
+ export { workspaceMembership } from './workspace-membership.js';
39
+ export type { WorkspaceMembership, NewWorkspaceMembership } from './workspace-membership.js';
37
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -32,7 +32,9 @@ export { serverBackups } from './server-backups.js';
32
32
  export { agentGroups, agentGroupMembers } from './agent-groups.js';
33
33
  export { unifiedEvents } from './unified-events.js';
34
34
  export { channelIdentities } from './channel-identities.js';
35
+ export { userIdentities } from './user-identities.js';
35
36
  export { personalAgents } from './personal-agents.js';
36
37
  export { builtSkills, builtSkillTools, builtChapters, builtChapterEdges, builtChapterTools, builtAgents, builtAgentSkills, builtTools, agentBuiltSkills, } from './builder.js';
37
38
  export { userPreferences } from './user-preferences.js';
39
+ export { workspaceMembership } from './workspace-membership.js';
38
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -195,7 +195,7 @@ export declare const personalAgents: import("drizzle-orm/sqlite-core").SQLiteTab
195
195
  tableName: "personal_agents";
196
196
  dataType: "string";
197
197
  columnType: "SQLiteText";
198
- data: "active" | "pending" | "provisioning" | "error";
198
+ data: "pending" | "provisioning" | "active" | "error";
199
199
  driverParam: string;
200
200
  notNull: true;
201
201
  hasDefault: true;
@@ -100,7 +100,7 @@ export declare const reliabilityEvents: import("drizzle-orm/sqlite-core").SQLite
100
100
  tableName: "reliability_events";
101
101
  dataType: "string";
102
102
  columnType: "SQLiteText";
103
- data: "critical" | "high" | "medium" | "low" | "ok";
103
+ data: "ok" | "critical" | "high" | "medium" | "low";
104
104
  driverParam: string;
105
105
  notNull: true;
106
106
  hasDefault: false;
@@ -269,7 +269,7 @@ export declare const serverProvisionConfigs: import("drizzle-orm/sqlite-core").S
269
269
  tableName: "server_provision_configs";
270
270
  dataType: "string";
271
271
  columnType: "SQLiteText";
272
- data: "loopback" | "all";
272
+ data: "all" | "loopback";
273
273
  driverParam: string;
274
274
  notNull: false;
275
275
  hasDefault: true;
@@ -121,7 +121,7 @@ export declare const sessionTasks: import("drizzle-orm/sqlite-core").SQLiteTable
121
121
  tableName: "session_tasks";
122
122
  dataType: "string";
123
123
  columnType: "SQLiteText";
124
- data: "backlog" | "todo" | "in_progress" | "done";
124
+ data: "todo" | "backlog" | "in_progress" | "done";
125
125
  driverParam: string;
126
126
  notNull: true;
127
127
  hasDefault: true;
@@ -119,7 +119,7 @@ export declare const skillExecutionStats: import("drizzle-orm/sqlite-core").SQLi
119
119
  tableName: "skill_execution_stats";
120
120
  dataType: "string";
121
121
  columnType: "SQLiteText";
122
- data: "error" | "ok" | "auth_error" | "timeout";
122
+ data: "ok" | "error" | "auth_error" | "timeout";
123
123
  driverParam: string;
124
124
  notNull: true;
125
125
  hasDefault: false;
@@ -102,7 +102,7 @@ export declare const tasks: import("drizzle-orm/sqlite-core").SQLiteTableWithCol
102
102
  tableName: "tasks";
103
103
  dataType: "string";
104
104
  columnType: "SQLiteText";
105
- data: "backlog" | "todo" | "in_progress" | "done";
105
+ data: "todo" | "backlog" | "in_progress" | "done";
106
106
  driverParam: string;
107
107
  notNull: true;
108
108
  hasDefault: true;
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Canonical per-user identity row. Covers OAuth providers (kind='oauth',
3
+ * e.g. google) and channel identities (kind='channel', e.g. whatsapp/telegram).
4
+ * Secret material (OAuth ADC blob) is stored app-level-encrypted as hex text
5
+ * in secretCiphertext/secretIv (same scheme as servers.token); null for
6
+ * channel identities that carry no secret.
7
+ */
8
+ export declare const userIdentities: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
9
+ name: "user_identities";
10
+ schema: undefined;
11
+ columns: {
12
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
13
+ name: "id";
14
+ tableName: "user_identities";
15
+ dataType: "string";
16
+ columnType: "SQLiteText";
17
+ data: string;
18
+ driverParam: string;
19
+ notNull: true;
20
+ hasDefault: false;
21
+ isPrimaryKey: true;
22
+ isAutoincrement: false;
23
+ hasRuntimeDefault: false;
24
+ enumValues: [string, ...string[]];
25
+ baseColumn: never;
26
+ identity: undefined;
27
+ generated: undefined;
28
+ }, {}, {
29
+ length: number | undefined;
30
+ }>;
31
+ userId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
32
+ name: "user_id";
33
+ tableName: "user_identities";
34
+ dataType: "string";
35
+ columnType: "SQLiteText";
36
+ data: string;
37
+ driverParam: string;
38
+ notNull: true;
39
+ hasDefault: false;
40
+ isPrimaryKey: false;
41
+ isAutoincrement: false;
42
+ hasRuntimeDefault: false;
43
+ enumValues: [string, ...string[]];
44
+ baseColumn: never;
45
+ identity: undefined;
46
+ generated: undefined;
47
+ }, {}, {
48
+ length: number | undefined;
49
+ }>;
50
+ provider: import("drizzle-orm/sqlite-core").SQLiteColumn<{
51
+ name: "provider";
52
+ tableName: "user_identities";
53
+ dataType: "string";
54
+ columnType: "SQLiteText";
55
+ data: string;
56
+ driverParam: string;
57
+ notNull: true;
58
+ hasDefault: false;
59
+ isPrimaryKey: false;
60
+ isAutoincrement: false;
61
+ hasRuntimeDefault: false;
62
+ enumValues: [string, ...string[]];
63
+ baseColumn: never;
64
+ identity: undefined;
65
+ generated: undefined;
66
+ }, {}, {
67
+ length: number | undefined;
68
+ }>;
69
+ kind: import("drizzle-orm/sqlite-core").SQLiteColumn<{
70
+ name: "kind";
71
+ tableName: "user_identities";
72
+ dataType: "string";
73
+ columnType: "SQLiteText";
74
+ data: string;
75
+ driverParam: string;
76
+ notNull: true;
77
+ hasDefault: false;
78
+ isPrimaryKey: false;
79
+ isAutoincrement: false;
80
+ hasRuntimeDefault: false;
81
+ enumValues: [string, ...string[]];
82
+ baseColumn: never;
83
+ identity: undefined;
84
+ generated: undefined;
85
+ }, {}, {
86
+ length: number | undefined;
87
+ }>;
88
+ externalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
89
+ name: "external_id";
90
+ tableName: "user_identities";
91
+ dataType: "string";
92
+ columnType: "SQLiteText";
93
+ data: string;
94
+ driverParam: string;
95
+ notNull: true;
96
+ hasDefault: false;
97
+ isPrimaryKey: false;
98
+ isAutoincrement: false;
99
+ hasRuntimeDefault: false;
100
+ enumValues: [string, ...string[]];
101
+ baseColumn: never;
102
+ identity: undefined;
103
+ generated: undefined;
104
+ }, {}, {
105
+ length: number | undefined;
106
+ }>;
107
+ displayName: import("drizzle-orm/sqlite-core").SQLiteColumn<{
108
+ name: "display_name";
109
+ tableName: "user_identities";
110
+ dataType: "string";
111
+ columnType: "SQLiteText";
112
+ data: string;
113
+ driverParam: string;
114
+ notNull: false;
115
+ hasDefault: false;
116
+ isPrimaryKey: false;
117
+ isAutoincrement: false;
118
+ hasRuntimeDefault: false;
119
+ enumValues: [string, ...string[]];
120
+ baseColumn: never;
121
+ identity: undefined;
122
+ generated: undefined;
123
+ }, {}, {
124
+ length: number | undefined;
125
+ }>;
126
+ scope: import("drizzle-orm/sqlite-core").SQLiteColumn<{
127
+ name: "scope";
128
+ tableName: "user_identities";
129
+ dataType: "string";
130
+ columnType: "SQLiteText";
131
+ data: string;
132
+ driverParam: string;
133
+ notNull: false;
134
+ hasDefault: false;
135
+ isPrimaryKey: false;
136
+ isAutoincrement: false;
137
+ hasRuntimeDefault: false;
138
+ enumValues: [string, ...string[]];
139
+ baseColumn: never;
140
+ identity: undefined;
141
+ generated: undefined;
142
+ }, {}, {
143
+ length: number | undefined;
144
+ }>;
145
+ secretCiphertext: import("drizzle-orm/sqlite-core").SQLiteColumn<{
146
+ name: "secret_ciphertext";
147
+ tableName: "user_identities";
148
+ dataType: "string";
149
+ columnType: "SQLiteText";
150
+ data: string;
151
+ driverParam: string;
152
+ notNull: false;
153
+ hasDefault: false;
154
+ isPrimaryKey: false;
155
+ isAutoincrement: false;
156
+ hasRuntimeDefault: false;
157
+ enumValues: [string, ...string[]];
158
+ baseColumn: never;
159
+ identity: undefined;
160
+ generated: undefined;
161
+ }, {}, {
162
+ length: number | undefined;
163
+ }>;
164
+ secretIv: import("drizzle-orm/sqlite-core").SQLiteColumn<{
165
+ name: "secret_iv";
166
+ tableName: "user_identities";
167
+ dataType: "string";
168
+ columnType: "SQLiteText";
169
+ data: string;
170
+ driverParam: string;
171
+ notNull: false;
172
+ hasDefault: false;
173
+ isPrimaryKey: false;
174
+ isAutoincrement: false;
175
+ hasRuntimeDefault: false;
176
+ enumValues: [string, ...string[]];
177
+ baseColumn: never;
178
+ identity: undefined;
179
+ generated: undefined;
180
+ }, {}, {
181
+ length: number | undefined;
182
+ }>;
183
+ expiresAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
184
+ name: "expires_at";
185
+ tableName: "user_identities";
186
+ dataType: "number";
187
+ columnType: "SQLiteInteger";
188
+ data: number;
189
+ driverParam: number;
190
+ notNull: false;
191
+ hasDefault: false;
192
+ isPrimaryKey: false;
193
+ isAutoincrement: false;
194
+ hasRuntimeDefault: false;
195
+ enumValues: undefined;
196
+ baseColumn: never;
197
+ identity: undefined;
198
+ generated: undefined;
199
+ }, {}, {}>;
200
+ verifiedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
201
+ name: "verified_at";
202
+ tableName: "user_identities";
203
+ dataType: "number";
204
+ columnType: "SQLiteInteger";
205
+ data: number;
206
+ driverParam: number;
207
+ notNull: false;
208
+ hasDefault: false;
209
+ isPrimaryKey: false;
210
+ isAutoincrement: false;
211
+ hasRuntimeDefault: false;
212
+ enumValues: undefined;
213
+ baseColumn: never;
214
+ identity: undefined;
215
+ generated: undefined;
216
+ }, {}, {}>;
217
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
218
+ name: "created_at";
219
+ tableName: "user_identities";
220
+ dataType: "number";
221
+ columnType: "SQLiteInteger";
222
+ data: number;
223
+ driverParam: number;
224
+ notNull: true;
225
+ hasDefault: false;
226
+ isPrimaryKey: false;
227
+ isAutoincrement: false;
228
+ hasRuntimeDefault: false;
229
+ enumValues: undefined;
230
+ baseColumn: never;
231
+ identity: undefined;
232
+ generated: undefined;
233
+ }, {}, {}>;
234
+ updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
235
+ name: "updated_at";
236
+ tableName: "user_identities";
237
+ dataType: "number";
238
+ columnType: "SQLiteInteger";
239
+ data: number;
240
+ driverParam: number;
241
+ notNull: true;
242
+ hasDefault: false;
243
+ isPrimaryKey: false;
244
+ isAutoincrement: false;
245
+ hasRuntimeDefault: false;
246
+ enumValues: undefined;
247
+ baseColumn: never;
248
+ identity: undefined;
249
+ generated: undefined;
250
+ }, {}, {}>;
251
+ };
252
+ dialect: "sqlite";
253
+ }>;
254
+ //# sourceMappingURL=user-identities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-identities.d.ts","sourceRoot":"","sources":["../../src/schema/user-identities.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuB1B,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { sqliteTable, text, integer, uniqueIndex, index } from 'drizzle-orm/sqlite-core';
2
+ import { user } from './auth/index.js';
3
+ /**
4
+ * Canonical per-user identity row. Covers OAuth providers (kind='oauth',
5
+ * e.g. google) and channel identities (kind='channel', e.g. whatsapp/telegram).
6
+ * Secret material (OAuth ADC blob) is stored app-level-encrypted as hex text
7
+ * in secretCiphertext/secretIv (same scheme as servers.token); null for
8
+ * channel identities that carry no secret.
9
+ */
10
+ export const userIdentities = sqliteTable('user_identities', {
11
+ id: text('id').primaryKey(),
12
+ userId: text('user_id')
13
+ .notNull()
14
+ .references(() => user.id, { onDelete: 'cascade' }),
15
+ provider: text('provider').notNull(), // 'google' | 'whatsapp' | 'telegram' | 'discord' | 'signal' | 'slack'
16
+ kind: text('kind').notNull(), // 'oauth' | 'channel'
17
+ externalId: text('external_id').notNull(),
18
+ displayName: text('display_name'),
19
+ scope: text('scope'),
20
+ secretCiphertext: text('secret_ciphertext'),
21
+ secretIv: text('secret_iv'),
22
+ expiresAt: integer('expires_at'),
23
+ verifiedAt: integer('verified_at'),
24
+ createdAt: integer('created_at').notNull(),
25
+ updatedAt: integer('updated_at').notNull(),
26
+ }, (t) => [
27
+ uniqueIndex('idx_user_identity_unique').on(t.provider, t.externalId),
28
+ index('idx_user_identity_user').on(t.userId),
29
+ ]);
30
+ //# sourceMappingURL=user-identities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-identities.js","sourceRoot":"","sources":["../../src/schema/user-identities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CACvC,iBAAiB,EACjB;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACrD,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,sEAAsE;IAC5G,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,sBAAsB;IACpD,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC;IACjC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;IACpB,gBAAgB,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAC3C,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC1C,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC3C,EACD,CAAC,CAAC,EAAE,EAAE,CAAC;IACL,WAAW,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC;IACpE,KAAK,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;CAC7C,CACF,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * workspace_membership — bridge between hub identity and Paperclip company tenancy.
3
+ *
4
+ * Each row means "user X holds role Y in Paperclip company Z".
5
+ * Composite PK: a user may belong to many Paperclip companies.
6
+ *
7
+ * Used by:
8
+ * - CompanySwitcher (Task 10): lists rows for the current user
9
+ * - JWT mint (Task 8): uses the selected row's paperclipCompanyId as the JWT companyId claim
10
+ */
11
+ export declare const workspaceMembership: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
12
+ name: "workspace_membership";
13
+ schema: undefined;
14
+ columns: {
15
+ userId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
16
+ name: "user_id";
17
+ tableName: "workspace_membership";
18
+ dataType: "string";
19
+ columnType: "SQLiteText";
20
+ data: string;
21
+ driverParam: string;
22
+ notNull: true;
23
+ hasDefault: false;
24
+ isPrimaryKey: false;
25
+ isAutoincrement: false;
26
+ hasRuntimeDefault: false;
27
+ enumValues: [string, ...string[]];
28
+ baseColumn: never;
29
+ identity: undefined;
30
+ generated: undefined;
31
+ }, {}, {
32
+ length: number | undefined;
33
+ }>;
34
+ paperclipCompanyId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
35
+ name: "paperclip_company_id";
36
+ tableName: "workspace_membership";
37
+ dataType: "string";
38
+ columnType: "SQLiteText";
39
+ data: string;
40
+ driverParam: string;
41
+ notNull: true;
42
+ hasDefault: false;
43
+ isPrimaryKey: false;
44
+ isAutoincrement: false;
45
+ hasRuntimeDefault: false;
46
+ enumValues: [string, ...string[]];
47
+ baseColumn: never;
48
+ identity: undefined;
49
+ generated: undefined;
50
+ }, {}, {
51
+ length: number | undefined;
52
+ }>;
53
+ role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
54
+ name: "role";
55
+ tableName: "workspace_membership";
56
+ dataType: "string";
57
+ columnType: "SQLiteText";
58
+ data: string;
59
+ driverParam: string;
60
+ notNull: true;
61
+ hasDefault: true;
62
+ isPrimaryKey: false;
63
+ isAutoincrement: false;
64
+ hasRuntimeDefault: false;
65
+ enumValues: [string, ...string[]];
66
+ baseColumn: never;
67
+ identity: undefined;
68
+ generated: undefined;
69
+ }, {}, {
70
+ length: number | undefined;
71
+ }>;
72
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
73
+ name: "created_at";
74
+ tableName: "workspace_membership";
75
+ dataType: "date";
76
+ columnType: "SQLiteTimestamp";
77
+ data: Date;
78
+ driverParam: number;
79
+ notNull: true;
80
+ hasDefault: false;
81
+ isPrimaryKey: false;
82
+ isAutoincrement: false;
83
+ hasRuntimeDefault: false;
84
+ enumValues: undefined;
85
+ baseColumn: never;
86
+ identity: undefined;
87
+ generated: undefined;
88
+ }, {}, {}>;
89
+ };
90
+ dialect: "sqlite";
91
+ }>;
92
+ export type WorkspaceMembership = typeof workspaceMembership.$inferSelect;
93
+ export type NewWorkspaceMembership = typeof workspaceMembership.$inferInsert;
94
+ //# sourceMappingURL=workspace-membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-membership.d.ts","sourceRoot":"","sources":["../../src/schema/workspace-membership.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc/B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAC;AAC1E,MAAM,MAAM,sBAAsB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { sqliteTable, text, integer, index, primaryKey } from 'drizzle-orm/sqlite-core';
2
+ import { user } from './auth/index.js';
3
+ /**
4
+ * workspace_membership — bridge between hub identity and Paperclip company tenancy.
5
+ *
6
+ * Each row means "user X holds role Y in Paperclip company Z".
7
+ * Composite PK: a user may belong to many Paperclip companies.
8
+ *
9
+ * Used by:
10
+ * - CompanySwitcher (Task 10): lists rows for the current user
11
+ * - JWT mint (Task 8): uses the selected row's paperclipCompanyId as the JWT companyId claim
12
+ */
13
+ export const workspaceMembership = sqliteTable('workspace_membership', {
14
+ userId: text('user_id')
15
+ .notNull()
16
+ .references(() => user.id, { onDelete: 'cascade' }),
17
+ paperclipCompanyId: text('paperclip_company_id').notNull(),
18
+ role: text('role').notNull().default('admin'),
19
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
20
+ }, (t) => [
21
+ primaryKey({ columns: [t.userId, t.paperclipCompanyId] }),
22
+ index('idx_workspace_membership_user').on(t.userId),
23
+ ]);
24
+ //# sourceMappingURL=workspace-membership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-membership.js","sourceRoot":"","sources":["../../src/schema/workspace-membership.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAC5C,sBAAsB,EACtB;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACrD,kBAAkB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE;IAC1D,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7C,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE;CAClE,EACD,CAAC,CAAC,EAAE,EAAE,CAAC;IACL,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC;IACzD,KAAK,CAAC,+BAA+B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;CACpD,CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minion-stack/db",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Drizzle ORM schema for the Minion shared database (LibSQL/Turso).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -24,6 +24,10 @@
24
24
  "types": "./dist/schema/auth/index.d.ts",
25
25
  "import": "./dist/schema/auth/index.js"
26
26
  },
27
+ "./pg": {
28
+ "types": "./dist/pg/schema/index.d.ts",
29
+ "import": "./dist/pg/schema/index.js"
30
+ },
27
31
  "./relations": {
28
32
  "types": "./dist/relations.d.ts",
29
33
  "import": "./dist/relations.js"
@@ -41,18 +45,23 @@
41
45
  "src",
42
46
  "README.md"
43
47
  ],
44
- "scripts": {
45
- "build": "tsc",
46
- "prepublishOnly": "tsc"
47
- },
48
48
  "peerDependencies": {
49
49
  "drizzle-orm": ">=0.45.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@minion-stack/tsconfig": "workspace:*",
53
52
  "@paralleldrive/cuid2": "^3.3.0",
54
- "drizzle-orm": "^0.45.1",
55
53
  "drizzle-kit": "^0.31.9",
56
- "typescript": "^5.0.0"
54
+ "drizzle-orm": "^0.45.1",
55
+ "oxlint": "^1.66.0",
56
+ "typescript": "^5.0.0",
57
+ "vitest": "^2.1.9",
58
+ "@minion-stack/tsconfig": "0.1.0"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc",
62
+ "typecheck": "tsc --noEmit",
63
+ "lint": "oxlint src",
64
+ "db:pg:generate": "drizzle-kit generate --config=drizzle.pg.config.ts",
65
+ "test": "vitest run"
57
66
  }
58
- }
67
+ }
@@ -0,0 +1,28 @@
1
+ import { describe, it, expect, beforeAll } from 'vitest';
2
+ import { sealSecret, openSecret } from './crypto.js';
3
+
4
+ beforeAll(() => {
5
+ process.env.ENCRYPTION_KEY = 'test-key-do-not-use-in-prod';
6
+ });
7
+
8
+ describe('identity secret crypto', () => {
9
+ it('round-trips a plaintext through seal/open', () => {
10
+ const plaintext = JSON.stringify({ type: 'authorized_user', refresh_token: 'abc123' });
11
+ const { ciphertext, iv } = sealSecret(plaintext);
12
+ expect(ciphertext).toMatch(/^[0-9a-f]+$/);
13
+ expect(iv).toMatch(/^[0-9a-f]+$/);
14
+ expect(openSecret(ciphertext, iv)).toBe(plaintext);
15
+ });
16
+
17
+ it('fails to open with a tampered ciphertext (GCM auth)', () => {
18
+ const { ciphertext, iv } = sealSecret('hello');
19
+ const tampered = ciphertext.slice(0, -2) + (ciphertext.endsWith('00') ? '11' : '00');
20
+ expect(() => openSecret(tampered, iv)).toThrow();
21
+ });
22
+
23
+ it('is wire-compatible with hub layout (ciphertext = hex(encrypted || authTag), 16-byte tag last)', () => {
24
+ const { ciphertext } = sealSecret('x');
25
+ // hex of (>=0 bytes ciphertext) + 16-byte tag → at least 32 hex chars of tag.
26
+ expect(ciphertext.length).toBeGreaterThanOrEqual(32);
27
+ });
28
+ });