@tearleads/client-sdk 0.1.38 → 0.1.40

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 (76) hide show
  1. package/client/Tearleads.d.ts +3 -0
  2. package/client/Tearleads.js +20 -12
  3. package/client/Tearleads.js.map +1 -1
  4. package/client/organizations/organizationGroupPresentation.d.ts +1 -12
  5. package/client/session/index.js +2 -2
  6. package/client/session/index.js.map +1 -1
  7. package/client/session/sessionOrganizationCreation.js +1 -0
  8. package/client/session/sessionOrganizationCreation.js.map +1 -1
  9. package/client/session/sessionTypes.d.ts +3 -0
  10. package/client/session/sessionTypes.js.map +1 -1
  11. package/client/workflowRuntime.d.ts +2 -0
  12. package/client/workflowRuntime.js +34 -16
  13. package/client/workflowRuntime.js.map +1 -1
  14. package/data/persistence/documents/documentDiscoveryEvidencePersistence.d.ts +16 -0
  15. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +23 -0
  16. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  17. package/data/persistence/organizations/organizationReadModelGrantPersistence.js +2 -1
  18. package/data/persistence/organizations/organizationReadModelGrantPersistence.js.map +1 -1
  19. package/data/persistence/organizations/organizationReadModelMemberLoad.d.ts +9 -0
  20. package/data/persistence/organizations/organizationReadModelMemberLoad.js +29 -21
  21. package/data/persistence/organizations/organizationReadModelMemberLoad.js.map +1 -1
  22. package/data/persistence/organizations/organizationReadModelMembershipPersistence.js +91 -46
  23. package/data/persistence/organizations/organizationReadModelMembershipPersistence.js.map +1 -1
  24. package/data/persistence/organizations/organizationReadModelPersistence.js +95 -73
  25. package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
  26. package/data/persistence/organizations/organizationReadModelProjection.js +78 -89
  27. package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
  28. package/data/persistence/organizations/organizationReadModelPurge.js +14 -15
  29. package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
  30. package/data/sqlite/organizationReadModelSchema.js +23 -28
  31. package/data/sqlite/organizationReadModelSchema.js.map +1 -1
  32. package/data/sqlite/organizationReadModelTableRegistry.d.ts +116 -263
  33. package/data/sqlite/organizationReadModelTableRegistry.js +10 -7
  34. package/data/sqlite/organizationReadModelTableRegistry.js.map +1 -1
  35. package/data/sqlite/schema.d.ts +116 -263
  36. package/data/sqlite/sqliteBindBudget.js +30 -0
  37. package/data/sqlite/sqliteBindBudget.js.map +1 -0
  38. package/data/trustedUserIdentity/index.d.ts +1 -1
  39. package/data/trustedUserIdentity/index.js +1 -1
  40. package/data/trustedUserIdentity/index.js.map +1 -1
  41. package/data/trustedUserIdentity/service.d.ts +12 -1
  42. package/data/trustedUserIdentity/service.js +27 -3
  43. package/data/trustedUserIdentity/service.js.map +1 -1
  44. package/internal/validators/operation/organizations.d.ts +0 -16
  45. package/internal/validators/response/index.d.ts +1 -1
  46. package/internal/validators/response/index.js.map +1 -1
  47. package/internal/validators/response/organizationReadModel.d.ts +10 -48
  48. package/internal/validators/response/organizationReadModel.js +9 -1
  49. package/internal/validators/response/organizationReadModel.js.map +1 -1
  50. package/package.json +1 -1
  51. package/workflows/organizations/createOrganization.d.ts +3 -0
  52. package/workflows/organizations/createOrganization.js +1 -0
  53. package/workflows/organizations/createOrganization.js.map +1 -1
  54. package/workflows/organizations/readModel.d.ts +8 -3
  55. package/workflows/organizations/readModel.js.map +1 -1
  56. package/workflows/organizations/readModelProjection.d.ts +2 -12
  57. package/workflows/organizations/readModelProjection.js +1 -1
  58. package/workflows/organizations/readModelProjection.js.map +1 -1
  59. package/workflows/registration/organizationProvisioningPersistence.d.ts +3 -0
  60. package/workflows/registration/organizationProvisioningPersistence.js +27 -1
  61. package/workflows/registration/organizationProvisioningPersistence.js.map +1 -1
  62. package/workflows/registration/persistRegistrationBootstrap.d.ts +3 -0
  63. package/workflows/registration/persistRegistrationBootstrap.js +7 -1
  64. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  65. package/workflows/registration/provisionedPrincipalHistory.d.ts +45 -0
  66. package/workflows/registration/provisionedPrincipalHistory.js +104 -0
  67. package/workflows/registration/provisionedPrincipalHistory.js.map +1 -0
  68. package/workflows/registration/provisioningAcknowledgement.js +18 -0
  69. package/workflows/registration/provisioningAcknowledgement.js.map +1 -1
  70. package/workflows/registration/registerIdentity.d.ts +3 -0
  71. package/workflows/registration/registerIdentity.js +1 -0
  72. package/workflows/registration/registerIdentity.js.map +1 -1
  73. package/workflows/sync/remoteReset.js +1 -3
  74. package/workflows/sync/remoteReset.js.map +1 -1
  75. package/data/persistence/organizations/organizationReadModelPolicyHeadPersistence.js +0 -64
  76. package/data/persistence/organizations/organizationReadModelPolicyHeadPersistence.js.map +0 -1
@@ -2905,6 +2905,114 @@ export declare const clientSQLiteSchema: {
2905
2905
  }, {}, {
2906
2906
  length: number | undefined;
2907
2907
  }>;
2908
+ memberGroupStateHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2909
+ name: "member_group_state_hash";
2910
+ tableName: "organization_read_model_state";
2911
+ dataType: "string";
2912
+ columnType: "SQLiteText";
2913
+ data: string;
2914
+ driverParam: string;
2915
+ notNull: true;
2916
+ hasDefault: false;
2917
+ isPrimaryKey: false;
2918
+ isAutoincrement: false;
2919
+ hasRuntimeDefault: false;
2920
+ enumValues: [string, ...string[]];
2921
+ baseColumn: never;
2922
+ identity: undefined;
2923
+ generated: undefined;
2924
+ }, {}, {
2925
+ length: number | undefined;
2926
+ }>;
2927
+ organizationStateHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2928
+ name: "organization_state_hash";
2929
+ tableName: "organization_read_model_state";
2930
+ dataType: "string";
2931
+ columnType: "SQLiteText";
2932
+ data: string;
2933
+ driverParam: string;
2934
+ notNull: true;
2935
+ hasDefault: false;
2936
+ isPrimaryKey: false;
2937
+ isAutoincrement: false;
2938
+ hasRuntimeDefault: false;
2939
+ enumValues: [string, ...string[]];
2940
+ baseColumn: never;
2941
+ identity: undefined;
2942
+ generated: undefined;
2943
+ }, {}, {
2944
+ length: number | undefined;
2945
+ }>;
2946
+ organizationStateVersion: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2947
+ name: "organization_state_version";
2948
+ tableName: "organization_read_model_state";
2949
+ dataType: "number";
2950
+ columnType: "SQLiteInteger";
2951
+ data: number;
2952
+ driverParam: number;
2953
+ notNull: true;
2954
+ hasDefault: false;
2955
+ isPrimaryKey: false;
2956
+ isAutoincrement: false;
2957
+ hasRuntimeDefault: false;
2958
+ enumValues: undefined;
2959
+ baseColumn: never;
2960
+ identity: undefined;
2961
+ generated: undefined;
2962
+ }, {}, {}>;
2963
+ organizationKeyEpoch: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2964
+ name: "organization_key_epoch";
2965
+ tableName: "organization_read_model_state";
2966
+ dataType: "number";
2967
+ columnType: "SQLiteInteger";
2968
+ data: number;
2969
+ driverParam: number;
2970
+ notNull: true;
2971
+ hasDefault: false;
2972
+ isPrimaryKey: false;
2973
+ isAutoincrement: false;
2974
+ hasRuntimeDefault: false;
2975
+ enumValues: undefined;
2976
+ baseColumn: never;
2977
+ identity: undefined;
2978
+ generated: undefined;
2979
+ }, {}, {}>;
2980
+ organizationKeyFingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2981
+ name: "organization_key_fingerprint";
2982
+ tableName: "organization_read_model_state";
2983
+ dataType: "string";
2984
+ columnType: "SQLiteText";
2985
+ data: string;
2986
+ driverParam: string;
2987
+ notNull: true;
2988
+ hasDefault: false;
2989
+ isPrimaryKey: false;
2990
+ isAutoincrement: false;
2991
+ hasRuntimeDefault: false;
2992
+ enumValues: [string, ...string[]];
2993
+ baseColumn: never;
2994
+ identity: undefined;
2995
+ generated: undefined;
2996
+ }, {}, {
2997
+ length: number | undefined;
2998
+ }>;
2999
+ organizationMemberCount: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3000
+ name: "organization_member_count";
3001
+ tableName: "organization_read_model_state";
3002
+ dataType: "number";
3003
+ columnType: "SQLiteInteger";
3004
+ data: number;
3005
+ driverParam: number;
3006
+ notNull: true;
3007
+ hasDefault: false;
3008
+ isPrimaryKey: false;
3009
+ isAutoincrement: false;
3010
+ hasRuntimeDefault: false;
3011
+ enumValues: undefined;
3012
+ baseColumn: never;
3013
+ identity: undefined;
3014
+ generated: undefined;
3015
+ }, {}, {}>;
2908
3016
  updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2909
3017
  name: "updated_at";
2910
3018
  tableName: "organization_read_model_state";
@@ -3463,148 +3571,14 @@ export declare const clientSQLiteSchema: {
3463
3571
  identity: undefined;
3464
3572
  generated: undefined;
3465
3573
  }, {}, {}>;
3466
- memberCount: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3467
- name: "member_count";
3468
- tableName: "organization_read_model_groups";
3469
- dataType: "number";
3470
- columnType: "SQLiteInteger";
3471
- data: number;
3472
- driverParam: number;
3473
- notNull: false;
3474
- hasDefault: false;
3475
- isPrimaryKey: false;
3476
- isAutoincrement: false;
3477
- hasRuntimeDefault: false;
3478
- enumValues: undefined;
3479
- baseColumn: never;
3480
- identity: undefined;
3481
- generated: undefined;
3482
- }, {}, {}>;
3483
- };
3484
- dialect: "sqlite";
3485
- }>;
3486
- organizationReadModelPolicyHeads: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
3487
- name: "organization_read_model_policy_heads";
3488
- schema: undefined;
3489
- columns: {
3490
- organizationId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3491
- name: "organization_id";
3492
- tableName: "organization_read_model_policy_heads";
3493
- dataType: "string";
3494
- columnType: "SQLiteText";
3495
- data: string;
3496
- driverParam: string;
3497
- notNull: true;
3498
- hasDefault: false;
3499
- isPrimaryKey: false;
3500
- isAutoincrement: false;
3501
- hasRuntimeDefault: false;
3502
- enumValues: [string, ...string[]];
3503
- baseColumn: never;
3504
- identity: undefined;
3505
- generated: undefined;
3506
- }, {}, {
3507
- length: number | undefined;
3508
- }>;
3509
- principalType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3510
- name: "principal_type";
3511
- tableName: "organization_read_model_policy_heads";
3512
- dataType: "string";
3513
- columnType: "SQLiteText";
3514
- data: string;
3515
- driverParam: string;
3516
- notNull: true;
3517
- hasDefault: false;
3518
- isPrimaryKey: false;
3519
- isAutoincrement: false;
3520
- hasRuntimeDefault: false;
3521
- enumValues: [string, ...string[]];
3522
- baseColumn: never;
3523
- identity: undefined;
3524
- generated: undefined;
3525
- }, {}, {
3526
- length: number | undefined;
3527
- }>;
3528
- principalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3529
- name: "principal_id";
3530
- tableName: "organization_read_model_policy_heads";
3531
- dataType: "string";
3532
- columnType: "SQLiteText";
3533
- data: string;
3534
- driverParam: string;
3535
- notNull: true;
3536
- hasDefault: false;
3537
- isPrimaryKey: false;
3538
- isAutoincrement: false;
3539
- hasRuntimeDefault: false;
3540
- enumValues: [string, ...string[]];
3541
- baseColumn: never;
3542
- identity: undefined;
3543
- generated: undefined;
3544
- }, {}, {
3545
- length: number | undefined;
3546
- }>;
3547
- stateHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3548
- name: "state_hash";
3549
- tableName: "organization_read_model_policy_heads";
3550
- dataType: "string";
3551
- columnType: "SQLiteText";
3552
- data: string;
3553
- driverParam: string;
3554
- notNull: true;
3555
- hasDefault: false;
3556
- isPrimaryKey: false;
3557
- isAutoincrement: false;
3558
- hasRuntimeDefault: false;
3559
- enumValues: [string, ...string[]];
3560
- baseColumn: never;
3561
- identity: undefined;
3562
- generated: undefined;
3563
- }, {}, {
3564
- length: number | undefined;
3565
- }>;
3566
- stateVersion: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3567
- name: "state_version";
3568
- tableName: "organization_read_model_policy_heads";
3569
- dataType: "number";
3570
- columnType: "SQLiteInteger";
3571
- data: number;
3572
- driverParam: number;
3573
- notNull: true;
3574
- hasDefault: false;
3575
- isPrimaryKey: false;
3576
- isAutoincrement: false;
3577
- hasRuntimeDefault: false;
3578
- enumValues: undefined;
3579
- baseColumn: never;
3580
- identity: undefined;
3581
- generated: undefined;
3582
- }, {}, {}>;
3583
- keyEpoch: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3584
- name: "key_epoch";
3585
- tableName: "organization_read_model_policy_heads";
3586
- dataType: "number";
3587
- columnType: "SQLiteInteger";
3588
- data: number;
3589
- driverParam: number;
3590
- notNull: true;
3591
- hasDefault: false;
3592
- isPrimaryKey: false;
3593
- isAutoincrement: false;
3594
- hasRuntimeDefault: false;
3595
- enumValues: undefined;
3596
- baseColumn: never;
3597
- identity: undefined;
3598
- generated: undefined;
3599
- }, {}, {}>;
3600
3574
  keyFingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3601
3575
  name: "key_fingerprint";
3602
- tableName: "organization_read_model_policy_heads";
3576
+ tableName: "organization_read_model_groups";
3603
3577
  dataType: "string";
3604
3578
  columnType: "SQLiteText";
3605
3579
  data: string;
3606
3580
  driverParam: string;
3607
- notNull: true;
3581
+ notNull: false;
3608
3582
  hasDefault: false;
3609
3583
  isPrimaryKey: false;
3610
3584
  isAutoincrement: false;
@@ -3618,12 +3592,12 @@ export declare const clientSQLiteSchema: {
3618
3592
  }>;
3619
3593
  memberCount: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3620
3594
  name: "member_count";
3621
- tableName: "organization_read_model_policy_heads";
3595
+ tableName: "organization_read_model_groups";
3622
3596
  dataType: "number";
3623
3597
  columnType: "SQLiteInteger";
3624
3598
  data: number;
3625
3599
  driverParam: number;
3626
- notNull: true;
3600
+ notNull: false;
3627
3601
  hasDefault: false;
3628
3602
  isPrimaryKey: false;
3629
3603
  isAutoincrement: false;
@@ -3633,59 +3607,14 @@ export declare const clientSQLiteSchema: {
3633
3607
  identity: undefined;
3634
3608
  generated: undefined;
3635
3609
  }, {}, {}>;
3636
- };
3637
- dialect: "sqlite";
3638
- }>;
3639
- organizationReadModelGroupMemberships: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
3640
- name: "organization_read_model_group_memberships";
3641
- schema: undefined;
3642
- columns: {
3643
- organizationId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3644
- name: "organization_id";
3645
- tableName: "organization_read_model_group_memberships";
3646
- dataType: "string";
3647
- columnType: "SQLiteText";
3648
- data: string;
3649
- driverParam: string;
3650
- notNull: true;
3651
- hasDefault: false;
3652
- isPrimaryKey: false;
3653
- isAutoincrement: false;
3654
- hasRuntimeDefault: false;
3655
- enumValues: [string, ...string[]];
3656
- baseColumn: never;
3657
- identity: undefined;
3658
- generated: undefined;
3659
- }, {}, {
3660
- length: number | undefined;
3661
- }>;
3662
- groupId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3663
- name: "group_id";
3664
- tableName: "organization_read_model_group_memberships";
3665
- dataType: "string";
3666
- columnType: "SQLiteText";
3667
- data: string;
3668
- driverParam: string;
3669
- notNull: true;
3670
- hasDefault: false;
3671
- isPrimaryKey: false;
3672
- isAutoincrement: false;
3673
- hasRuntimeDefault: false;
3674
- enumValues: [string, ...string[]];
3675
- baseColumn: never;
3676
- identity: undefined;
3677
- generated: undefined;
3678
- }, {}, {
3679
- length: number | undefined;
3680
- }>;
3681
- stateHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3682
- name: "state_hash";
3683
- tableName: "organization_read_model_group_memberships";
3610
+ membersStateHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3611
+ name: "members_state_hash";
3612
+ tableName: "organization_read_model_groups";
3684
3613
  dataType: "string";
3685
3614
  columnType: "SQLiteText";
3686
3615
  data: string;
3687
3616
  driverParam: string;
3688
- notNull: true;
3617
+ notNull: false;
3689
3618
  hasDefault: false;
3690
3619
  isPrimaryKey: false;
3691
3620
  isAutoincrement: false;
@@ -3816,82 +3745,6 @@ export declare const clientSQLiteSchema: {
3816
3745
  }, {}, {
3817
3746
  length: number | undefined;
3818
3747
  }>;
3819
- signingKeyFingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3820
- name: "signing_key_fingerprint";
3821
- tableName: "organization_read_model_group_members";
3822
- dataType: "string";
3823
- columnType: "SQLiteText";
3824
- data: string;
3825
- driverParam: string;
3826
- notNull: false;
3827
- hasDefault: false;
3828
- isPrimaryKey: false;
3829
- isAutoincrement: false;
3830
- hasRuntimeDefault: false;
3831
- enumValues: [string, ...string[]];
3832
- baseColumn: never;
3833
- identity: undefined;
3834
- generated: undefined;
3835
- }, {}, {
3836
- length: number | undefined;
3837
- }>;
3838
- signingPublicKey: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3839
- name: "signing_public_key";
3840
- tableName: "organization_read_model_group_members";
3841
- dataType: "string";
3842
- columnType: "SQLiteText";
3843
- data: string;
3844
- driverParam: string;
3845
- notNull: false;
3846
- hasDefault: false;
3847
- isPrimaryKey: false;
3848
- isAutoincrement: false;
3849
- hasRuntimeDefault: false;
3850
- enumValues: [string, ...string[]];
3851
- baseColumn: never;
3852
- identity: undefined;
3853
- generated: undefined;
3854
- }, {}, {
3855
- length: number | undefined;
3856
- }>;
3857
- encapsulationPublicKey: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3858
- name: "encapsulation_public_key";
3859
- tableName: "organization_read_model_group_members";
3860
- dataType: "string";
3861
- columnType: "SQLiteText";
3862
- data: string;
3863
- driverParam: string;
3864
- notNull: false;
3865
- hasDefault: false;
3866
- isPrimaryKey: false;
3867
- isAutoincrement: false;
3868
- hasRuntimeDefault: false;
3869
- enumValues: [string, ...string[]];
3870
- baseColumn: never;
3871
- identity: undefined;
3872
- generated: undefined;
3873
- }, {}, {
3874
- length: number | undefined;
3875
- }>;
3876
- encapsulationKeyFingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
3877
- name: "encapsulation_key_fingerprint";
3878
- tableName: "organization_read_model_group_members";
3879
- dataType: "string";
3880
- columnType: "SQLiteText";
3881
- data: string;
3882
- driverParam: string;
3883
- notNull: false;
3884
- hasDefault: false;
3885
- isPrimaryKey: false;
3886
- isAutoincrement: false;
3887
- hasRuntimeDefault: false;
3888
- enumValues: [string, ...string[]];
3889
- baseColumn: never;
3890
- identity: undefined;
3891
- generated: undefined;
3892
- }, {}, {
3893
- length: number | undefined;
3894
- }>;
3895
3748
  };
3896
3749
  dialect: "sqlite";
3897
3750
  }>;
@@ -0,0 +1,30 @@
1
+ import { getTableColumns } from "drizzle-orm";
2
+ /**
3
+ * SQLite's historical default `SQLITE_MAX_VARIABLE_NUMBER`. Some hosts raise
4
+ * it, but the SDK runs on several SQLite builds, so every statement it batches
5
+ * stays within this budget.
6
+ */
7
+ export const SQLITE_BOUND_VARIABLE_BUDGET = 999;
8
+ /**
9
+ * Rows (or list entries) one statement may carry when each binds
10
+ * `variablesPerRow` values on top of `fixedVariables` shared ones.
11
+ */
12
+ export function sqliteRowsPerStatement(variablesPerRow, fixedVariables = 0) {
13
+ const rows = Math.floor((SQLITE_BOUND_VARIABLE_BUDGET - fixedVariables) / variablesPerRow);
14
+ if (!Number.isInteger(variablesPerRow) ||
15
+ variablesPerRow < 1 ||
16
+ !Number.isInteger(fixedVariables) ||
17
+ fixedVariables < 0 ||
18
+ rows < 1) {
19
+ throw new Error("SQLite statement cannot fit its bound variables");
20
+ }
21
+ return rows;
22
+ }
23
+ /**
24
+ * Rows per multi-row INSERT into `table`. Every column may bind one value,
25
+ * including explicit nulls, so the column count is the per-row ceiling.
26
+ */
27
+ export function sqliteInsertBatchSize(table) {
28
+ return sqliteRowsPerStatement(Object.keys(getTableColumns(table)).length);
29
+ }
30
+ //# sourceMappingURL=sqliteBindBudget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqliteBindBudget.js","sourceRoot":"","sources":["sqliteBindBudget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,eAAuB,EACvB,cAAc,GAAG,CAAC;IAElB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,CAAC,4BAA4B,GAAG,cAAc,CAAC,GAAG,eAAe,CAClE,CAAC;IACF,IACE,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC;QAClC,eAAe,GAAG,CAAC;QACnB,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC;QACjC,cAAc,GAAG,CAAC;QAClB,IAAI,GAAG,CAAC,EACR,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACtD,OAAO,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5E,CAAC","sourcesContent":["import { getTableColumns } from \"drizzle-orm\";\nimport type { SQLiteTable } from \"drizzle-orm/sqlite-core\";\n\n/**\n * SQLite's historical default `SQLITE_MAX_VARIABLE_NUMBER`. Some hosts raise\n * it, but the SDK runs on several SQLite builds, so every statement it batches\n * stays within this budget.\n */\nexport const SQLITE_BOUND_VARIABLE_BUDGET = 999;\n\n/**\n * Rows (or list entries) one statement may carry when each binds\n * `variablesPerRow` values on top of `fixedVariables` shared ones.\n */\nexport function sqliteRowsPerStatement(\n variablesPerRow: number,\n fixedVariables = 0,\n): number {\n const rows = Math.floor(\n (SQLITE_BOUND_VARIABLE_BUDGET - fixedVariables) / variablesPerRow,\n );\n if (\n !Number.isInteger(variablesPerRow) ||\n variablesPerRow < 1 ||\n !Number.isInteger(fixedVariables) ||\n fixedVariables < 0 ||\n rows < 1\n ) {\n throw new Error(\"SQLite statement cannot fit its bound variables\");\n }\n return rows;\n}\n\n/**\n * Rows per multi-row INSERT into `table`. Every column may bind one value,\n * including explicit nulls, so the column count is the per-row ceiling.\n */\nexport function sqliteInsertBatchSize(table: SQLiteTable): number {\n return sqliteRowsPerStatement(Object.keys(getTableColumns(table)).length);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  export { createApiUserIdentitySource } from "./apiAdapter.js";
2
2
  export { requireTrustedUserIdentityResolver } from "./requiredResolver.js";
3
- export { createTrustedUserIdentityService } from "./service.js";
3
+ export { createTrustedUserIdentityService, loadPinnedUserIdentity, } from "./service.js";
4
4
  export { resolveIdentityTrustDomain } from "./trustDomain.js";
5
5
  export type { LocalUserIdentityCandidate, TrustedUserIdentity, TrustedUserIdentityResolver, } from "./types.js";
6
6
  export { validateUserIdentityKeys } from "./validation.js";
@@ -1,6 +1,6 @@
1
1
  export { createApiUserIdentitySource } from "./apiAdapter.js";
2
2
  export { requireTrustedUserIdentityResolver } from "./requiredResolver.js";
3
- export { createTrustedUserIdentityService } from "./service.js";
3
+ export { createTrustedUserIdentityService, loadPinnedUserIdentity, } from "./service.js";
4
4
  export { resolveIdentityTrustDomain } from "./trustDomain.js";
5
5
  export { validateUserIdentityKeys } from "./validation.js";
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,kCAAkC,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,gCAAgC,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { createApiUserIdentitySource } from \"./apiAdapter\";\nexport { requireTrustedUserIdentityResolver } from \"./requiredResolver\";\nexport { createTrustedUserIdentityService } from \"./service\";\nexport { resolveIdentityTrustDomain } from \"./trustDomain\";\nexport type {\n LocalUserIdentityCandidate,\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"./types\";\nexport { validateUserIdentityKeys } from \"./validation\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,kCAAkC,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,gCAAgC,EAChC,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { createApiUserIdentitySource } from \"./apiAdapter\";\nexport { requireTrustedUserIdentityResolver } from \"./requiredResolver\";\nexport {\n createTrustedUserIdentityService,\n loadPinnedUserIdentity,\n} from \"./service\";\nexport { resolveIdentityTrustDomain } from \"./trustDomain\";\nexport type {\n LocalUserIdentityCandidate,\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"./types\";\nexport { validateUserIdentityKeys } from \"./validation\";\n"]}
@@ -1,2 +1,13 @@
1
- import { type TrustedUserIdentityService, type TrustedUserIdentityServiceDependencies } from "./types.js";
1
+ import type { ExecSql } from "../sqlite/sqlSchema.js";
2
+ import { type TrustedUserIdentity, type TrustedUserIdentityService, type TrustedUserIdentityServiceDependencies } from "./types.js";
3
+ /**
4
+ * Read-only: the identity this trust store already pins for `userId`, or null.
5
+ * The stored keys must still match their stored fingerprints. Never inserts,
6
+ * compares against or replaces a pin.
7
+ */
8
+ export declare function loadPinnedUserIdentity(input: {
9
+ readonly execSql: ExecSql;
10
+ readonly identityTrustDomain: string;
11
+ readonly userId: string;
12
+ }): Promise<TrustedUserIdentity | null>;
2
13
  export declare function createTrustedUserIdentityService(dependencies: TrustedUserIdentityServiceDependencies): TrustedUserIdentityService;
@@ -1,10 +1,10 @@
1
1
  import { KeyingVerificationError } from "../../internal/crypto/index.js";
2
- import { bytesToBase64 } from "../../internal/encoding/index.js";
3
- import { compareOrInsertTrustedUserIdentityPin, loadTrustedUserIdForSigningKey, TrustedUserIdentityPinCorruptError, TrustedUserIdentityPinMismatchError, } from "../persistence/trustedUserIdentityPinPersistence.js";
2
+ import { base64ToBytes, bytesToBase64 } from "../../internal/encoding/index.js";
3
+ import { compareOrInsertTrustedUserIdentityPin, loadTrustedUserIdentityPin, loadTrustedUserIdForSigningKey, TrustedUserIdentityPinCorruptError, TrustedUserIdentityPinMismatchError, } from "../persistence/trustedUserIdentityPinPersistence.js";
4
4
  import { TrustedUserIdentityPinContentionError } from "../persistence/trustedUserIdentityPinTransaction.js";
5
5
  import { DatabaseUnavailableError } from "../sync/databaseUnavailable.js";
6
6
  import { brandTrustedUserIdentity, TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE, TRUSTED_USER_IDENTITY_FORMAT_VERSION, TRUSTED_USER_IDENTITY_SIGNING_SUITE, } from "./types.js";
7
- import { assertTrustedUserIdentityUserId, validateLocalUserIdentity, validateRemoteUserIdentity, } from "./validation.js";
7
+ import { assertTrustedUserIdentityUserId, validateLocalUserIdentity, validateRemoteUserIdentity, validateUserIdentityKeys, } from "./validation.js";
8
8
  function requireTrustStore(dependencies) {
9
9
  // A missing trust domain is a static misconfiguration and must stay loud.
10
10
  if (!dependencies.identityTrustDomain) {
@@ -85,6 +85,30 @@ async function pinIdentity(input) {
85
85
  });
86
86
  return brandTrustedUserIdentity(input.identity);
87
87
  }
88
+ /**
89
+ * Read-only: the identity this trust store already pins for `userId`, or null.
90
+ * The stored keys must still match their stored fingerprints. Never inserts,
91
+ * compares against or replaces a pin.
92
+ */
93
+ export async function loadPinnedUserIdentity(input) {
94
+ assertTrustedUserIdentityUserId(input.userId);
95
+ const pin = await loadTrustedUserIdentityPin(input);
96
+ if (!pin)
97
+ return null;
98
+ const keys = await validateUserIdentityKeys({
99
+ candidate: {
100
+ encapsulationPublicKey: base64ToBytes(pin.encapsulationPublicKey),
101
+ signingKeyFingerprint: pin.signingKeyFingerprint,
102
+ signingPublicKey: base64ToBytes(pin.signingPublicKey),
103
+ },
104
+ encapsulationKeyFingerprint: pin.encapsulationKeyFingerprint,
105
+ });
106
+ return brandTrustedUserIdentity({
107
+ ...keys,
108
+ identityTrustDomain: input.identityTrustDomain,
109
+ userId: input.userId,
110
+ });
111
+ }
88
112
  export function createTrustedUserIdentityService(dependencies) {
89
113
  return {
90
114
  async boundUserId(signingKeyFingerprint) {
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["service.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n compareOrInsertTrustedUserIdentityPin,\n loadTrustedUserIdForSigningKey,\n TrustedUserIdentityPinCorruptError,\n TrustedUserIdentityPinMismatchError,\n} from \"../persistence/trustedUserIdentityPinPersistence\";\nimport { TrustedUserIdentityPinContentionError } from \"../persistence/trustedUserIdentityPinTransaction\";\nimport { DatabaseUnavailableError } from \"../sync/databaseUnavailable\";\nimport {\n brandTrustedUserIdentity,\n TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n type TrustedUserIdentity,\n type TrustedUserIdentityService,\n type TrustedUserIdentityServiceDependencies,\n type ValidatedUserIdentityCandidate,\n} from \"./types\";\nimport {\n assertTrustedUserIdentityUserId,\n validateLocalUserIdentity,\n validateRemoteUserIdentity,\n} from \"./validation\";\n\nfunction requireTrustStore(\n dependencies: TrustedUserIdentityServiceDependencies,\n): {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identityTrustDomain: string;\n} {\n // A missing trust domain is a static misconfiguration and must stay loud.\n if (!dependencies.identityTrustDomain) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Trusted user identity resolution requires a stable API trust domain\",\n );\n }\n // An absent trust store is not: getExecSql() returns null exactly while the\n // database is not ready, which happens routinely when the runtime is swapped\n // under in-flight sync work. Callers that tolerate a vanishing database\n // discriminate on the error type, so this must not share the code above.\n const execSql = dependencies.getExecSql();\n if (!execSql) {\n throw new DatabaseUnavailableError(\n \"Trusted user identity resolution requires a ready SQLite trust store\",\n );\n }\n return { execSql, identityTrustDomain: dependencies.identityTrustDomain };\n}\n\nasync function compareWithDurablePin(input: {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly firstSeenAt: string;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<void> {\n try {\n await compareOrInsertTrustedUserIdentityPin({\n execSql: input.execSql,\n pin: {\n encapsulationKeyFingerprint: input.identity.encapsulationKeyFingerprint,\n encapsulationPublicKey: bytesToBase64(\n input.identity.encapsulationPublicKey,\n ),\n encapsulationSuite: TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n firstSeenAt: input.firstSeenAt,\n formatVersion: TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n identityTrustDomain: input.identity.identityTrustDomain,\n signingKeyFingerprint: input.identity.signingKeyFingerprint,\n signingPublicKey: bytesToBase64(input.identity.signingPublicKey),\n signingSuite: TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n userId: input.identity.userId,\n },\n });\n } catch (error) {\n if (error instanceof TrustedUserIdentityPinMismatchError) {\n throw new KeyingVerificationError(\n \"equivocation\",\n error.existing.userId !== error.candidate.userId\n ? `Signing key for ${input.identity.userId} is already bound to ${error.existing.userId}`\n : `Trusted user identity changed for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinCorruptError) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n `Trusted user identity pin is corrupt for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinContentionError) {\n // Lock contention says nothing about the identity; the caller retries\n // once the trust store is free, so this must not be recordable evidence.\n throw new DatabaseUnavailableError(\n `Trusted user identity pin store is busy for ${input.identity.userId}`,\n );\n }\n throw error;\n }\n}\n\nasync function resolveCandidate(\n dependencies: TrustedUserIdentityServiceDependencies,\n userId: string,\n identityTrustDomain: string,\n): Promise<ValidatedUserIdentityCandidate | null> {\n const localUserId = dependencies.getLocalUserId();\n if (userId === localUserId) {\n const localIdentity = dependencies.getLocalIdentity(userId);\n if (!localIdentity) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Authoritative local identity keys are unavailable\",\n );\n }\n return validateLocalUserIdentity({\n candidate: localIdentity,\n identityTrustDomain,\n userId,\n });\n }\n\n const remoteIdentity = await dependencies.remoteSource.load(userId);\n return remoteIdentity\n ? validateRemoteUserIdentity({\n candidate: remoteIdentity,\n identityTrustDomain,\n requestedUserId: userId,\n })\n : null;\n}\n\nasync function pinIdentity(input: {\n readonly dependencies: TrustedUserIdentityServiceDependencies;\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<TrustedUserIdentity> {\n await compareWithDurablePin({\n execSql: input.execSql,\n firstSeenAt: (input.dependencies.now?.() ?? new Date()).toISOString(),\n identity: input.identity,\n });\n return brandTrustedUserIdentity(input.identity);\n}\n\nexport function createTrustedUserIdentityService(\n dependencies: TrustedUserIdentityServiceDependencies,\n): TrustedUserIdentityService {\n return {\n async boundUserId(signingKeyFingerprint) {\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n return loadTrustedUserIdForSigningKey({\n execSql,\n identityTrustDomain,\n signingKeyFingerprint,\n });\n },\n async pinLocal(userId, candidate) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n const identity = await validateLocalUserIdentity({\n candidate,\n identityTrustDomain,\n userId,\n });\n return pinIdentity({ dependencies, execSql, identity });\n },\n async resolve(userId) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n try {\n const identity = await resolveCandidate(\n dependencies,\n userId,\n identityTrustDomain,\n );\n if (!identity) {\n return null;\n }\n return await pinIdentity({ dependencies, execSql, identity });\n } catch (error) {\n dependencies.remoteSource.invalidate(userId);\n throw error;\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["service.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n compareOrInsertTrustedUserIdentityPin,\n loadTrustedUserIdentityPin,\n loadTrustedUserIdForSigningKey,\n TrustedUserIdentityPinCorruptError,\n TrustedUserIdentityPinMismatchError,\n} from \"../persistence/trustedUserIdentityPinPersistence\";\nimport { TrustedUserIdentityPinContentionError } from \"../persistence/trustedUserIdentityPinTransaction\";\nimport type { ExecSql } from \"../sqlite/sqlSchema\";\nimport { DatabaseUnavailableError } from \"../sync/databaseUnavailable\";\nimport {\n brandTrustedUserIdentity,\n TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n type TrustedUserIdentity,\n type TrustedUserIdentityService,\n type TrustedUserIdentityServiceDependencies,\n type ValidatedUserIdentityCandidate,\n} from \"./types\";\nimport {\n assertTrustedUserIdentityUserId,\n validateLocalUserIdentity,\n validateRemoteUserIdentity,\n validateUserIdentityKeys,\n} from \"./validation\";\n\nfunction requireTrustStore(\n dependencies: TrustedUserIdentityServiceDependencies,\n): {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identityTrustDomain: string;\n} {\n // A missing trust domain is a static misconfiguration and must stay loud.\n if (!dependencies.identityTrustDomain) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Trusted user identity resolution requires a stable API trust domain\",\n );\n }\n // An absent trust store is not: getExecSql() returns null exactly while the\n // database is not ready, which happens routinely when the runtime is swapped\n // under in-flight sync work. Callers that tolerate a vanishing database\n // discriminate on the error type, so this must not share the code above.\n const execSql = dependencies.getExecSql();\n if (!execSql) {\n throw new DatabaseUnavailableError(\n \"Trusted user identity resolution requires a ready SQLite trust store\",\n );\n }\n return { execSql, identityTrustDomain: dependencies.identityTrustDomain };\n}\n\nasync function compareWithDurablePin(input: {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly firstSeenAt: string;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<void> {\n try {\n await compareOrInsertTrustedUserIdentityPin({\n execSql: input.execSql,\n pin: {\n encapsulationKeyFingerprint: input.identity.encapsulationKeyFingerprint,\n encapsulationPublicKey: bytesToBase64(\n input.identity.encapsulationPublicKey,\n ),\n encapsulationSuite: TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n firstSeenAt: input.firstSeenAt,\n formatVersion: TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n identityTrustDomain: input.identity.identityTrustDomain,\n signingKeyFingerprint: input.identity.signingKeyFingerprint,\n signingPublicKey: bytesToBase64(input.identity.signingPublicKey),\n signingSuite: TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n userId: input.identity.userId,\n },\n });\n } catch (error) {\n if (error instanceof TrustedUserIdentityPinMismatchError) {\n throw new KeyingVerificationError(\n \"equivocation\",\n error.existing.userId !== error.candidate.userId\n ? `Signing key for ${input.identity.userId} is already bound to ${error.existing.userId}`\n : `Trusted user identity changed for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinCorruptError) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n `Trusted user identity pin is corrupt for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinContentionError) {\n // Lock contention says nothing about the identity; the caller retries\n // once the trust store is free, so this must not be recordable evidence.\n throw new DatabaseUnavailableError(\n `Trusted user identity pin store is busy for ${input.identity.userId}`,\n );\n }\n throw error;\n }\n}\n\nasync function resolveCandidate(\n dependencies: TrustedUserIdentityServiceDependencies,\n userId: string,\n identityTrustDomain: string,\n): Promise<ValidatedUserIdentityCandidate | null> {\n const localUserId = dependencies.getLocalUserId();\n if (userId === localUserId) {\n const localIdentity = dependencies.getLocalIdentity(userId);\n if (!localIdentity) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Authoritative local identity keys are unavailable\",\n );\n }\n return validateLocalUserIdentity({\n candidate: localIdentity,\n identityTrustDomain,\n userId,\n });\n }\n\n const remoteIdentity = await dependencies.remoteSource.load(userId);\n return remoteIdentity\n ? validateRemoteUserIdentity({\n candidate: remoteIdentity,\n identityTrustDomain,\n requestedUserId: userId,\n })\n : null;\n}\n\nasync function pinIdentity(input: {\n readonly dependencies: TrustedUserIdentityServiceDependencies;\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<TrustedUserIdentity> {\n await compareWithDurablePin({\n execSql: input.execSql,\n firstSeenAt: (input.dependencies.now?.() ?? new Date()).toISOString(),\n identity: input.identity,\n });\n return brandTrustedUserIdentity(input.identity);\n}\n\n/**\n * Read-only: the identity this trust store already pins for `userId`, or null.\n * The stored keys must still match their stored fingerprints. Never inserts,\n * compares against or replaces a pin.\n */\nexport async function loadPinnedUserIdentity(input: {\n readonly execSql: ExecSql;\n readonly identityTrustDomain: string;\n readonly userId: string;\n}): Promise<TrustedUserIdentity | null> {\n assertTrustedUserIdentityUserId(input.userId);\n const pin = await loadTrustedUserIdentityPin(input);\n if (!pin) return null;\n const keys = await validateUserIdentityKeys({\n candidate: {\n encapsulationPublicKey: base64ToBytes(pin.encapsulationPublicKey),\n signingKeyFingerprint: pin.signingKeyFingerprint,\n signingPublicKey: base64ToBytes(pin.signingPublicKey),\n },\n encapsulationKeyFingerprint: pin.encapsulationKeyFingerprint,\n });\n return brandTrustedUserIdentity({\n ...keys,\n identityTrustDomain: input.identityTrustDomain,\n userId: input.userId,\n });\n}\n\nexport function createTrustedUserIdentityService(\n dependencies: TrustedUserIdentityServiceDependencies,\n): TrustedUserIdentityService {\n return {\n async boundUserId(signingKeyFingerprint) {\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n return loadTrustedUserIdForSigningKey({\n execSql,\n identityTrustDomain,\n signingKeyFingerprint,\n });\n },\n async pinLocal(userId, candidate) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n const identity = await validateLocalUserIdentity({\n candidate,\n identityTrustDomain,\n userId,\n });\n return pinIdentity({ dependencies, execSql, identity });\n },\n async resolve(userId) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n try {\n const identity = await resolveCandidate(\n dependencies,\n userId,\n identityTrustDomain,\n );\n if (!identity) {\n return null;\n }\n return await pinIdentity({ dependencies, execSql, identity });\n } catch (error) {\n dependencies.remoteSource.invalidate(userId);\n throw error;\n }\n },\n };\n}\n"]}
@@ -7922,22 +7922,14 @@ export declare const getOrganizationReadModelOperation: Omit<{
7922
7922
  groups: z.ZodCustom<{
7923
7923
  groupId: string;
7924
7924
  members: {
7925
- encapsulationKeyFingerprint: string | null;
7926
- encapsulationPublicKey: string | null;
7927
7925
  role: "member" | "admin";
7928
- signingKeyFingerprint: string | null;
7929
- signingPublicKey: string | null;
7930
7926
  userId: string;
7931
7927
  }[];
7932
7928
  stateHash: string;
7933
7929
  }[], {
7934
7930
  groupId: string;
7935
7931
  members: {
7936
- encapsulationKeyFingerprint: string | null;
7937
- encapsulationPublicKey: string | null;
7938
7932
  role: "member" | "admin";
7939
- signingKeyFingerprint: string | null;
7940
- signingPublicKey: string | null;
7941
7933
  userId: string;
7942
7934
  }[];
7943
7935
  stateHash: string;
@@ -8071,22 +8063,14 @@ export declare const getOrganizationReadModelOperation: Omit<{
8071
8063
  groups: z.ZodCustom<{
8072
8064
  groupId: string;
8073
8065
  members: {
8074
- encapsulationKeyFingerprint: string | null;
8075
- encapsulationPublicKey: string | null;
8076
8066
  role: "member" | "admin";
8077
- signingKeyFingerprint: string | null;
8078
- signingPublicKey: string | null;
8079
8067
  userId: string;
8080
8068
  }[];
8081
8069
  stateHash: string;
8082
8070
  }[], {
8083
8071
  groupId: string;
8084
8072
  members: {
8085
- encapsulationKeyFingerprint: string | null;
8086
- encapsulationPublicKey: string | null;
8087
8073
  role: "member" | "admin";
8088
- signingKeyFingerprint: string | null;
8089
- signingPublicKey: string | null;
8090
8074
  userId: string;
8091
8075
  }[];
8092
8076
  stateHash: string;