@peers-app/peers-sdk 0.26.5 → 0.26.6
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/data/group-members.d.ts +6 -1
- package/dist/data/group-members.js +12 -4
- package/dist/data/groups.d.ts +6 -1
- package/dist/data/groups.js +12 -4
- package/dist/data/package-versions.d.ts +5 -1
- package/dist/data/package-versions.js +11 -4
- package/dist/data/packages.d.ts +7 -1
- package/dist/data/packages.js +13 -4
- package/dist/data/table-signing.test.d.ts +1 -0
- package/dist/data/table-signing.test.js +118 -0
- package/dist/data/users.d.ts +1 -2
- package/dist/data/users.js +8 -5
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import type { DataContext } from "../context/data-context";
|
|
|
3
3
|
import { GroupMemberRole } from "./group-member-roles";
|
|
4
4
|
import type { ISaveOptions } from "./orm/data-query";
|
|
5
5
|
import { Table } from "./orm/table";
|
|
6
|
+
/** Schema for a signed group membership, including its role and soft deletion state. */
|
|
6
7
|
export declare const groupMemberSchema: z.ZodObject<{
|
|
7
8
|
groupMemberId: z.ZodEffects<z.ZodString, string, string>;
|
|
8
9
|
groupId: z.ZodEffects<z.ZodString, string, string>;
|
|
@@ -25,18 +26,22 @@ export declare const groupMemberSchema: z.ZodObject<{
|
|
|
25
26
|
groupMemberId: string;
|
|
26
27
|
deleted?: boolean | undefined;
|
|
27
28
|
}>;
|
|
29
|
+
/** A signed association between a user and a group with an assigned role. */
|
|
28
30
|
export type IGroupMember = z.infer<typeof groupMemberSchema>;
|
|
31
|
+
/** System table name for group membership records. */
|
|
29
32
|
export declare const groupMembersTableName = "GroupMembers";
|
|
33
|
+
/** Group membership table with signature checks and signed soft deletion. */
|
|
30
34
|
export declare class GroupMembersTable extends Table<IGroupMember> {
|
|
31
35
|
static isPassthrough: boolean;
|
|
32
36
|
save(groupMember: IGroupMember, opts?: ISaveOptions): Promise<IGroupMember>;
|
|
33
37
|
signAndSave(groupMember: IGroupMember, opts?: ISaveOptions): Promise<IGroupMember>;
|
|
34
38
|
delete(groupMemberId: string): Promise<void>;
|
|
35
|
-
|
|
39
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
36
40
|
static enableGroupMemberSigning(fn: (groupMember: IGroupMember) => IGroupMember): void;
|
|
37
41
|
/** @deprecated Forbidden on GroupsTable; use save() */
|
|
38
42
|
insert(..._args: Parameters<Table<IGroupMember>["insert"]>): never;
|
|
39
43
|
/** @deprecated Forbidden on GroupsTable; use save() */
|
|
40
44
|
update(..._args: Parameters<Table<IGroupMember>["update"]>): never;
|
|
41
45
|
}
|
|
46
|
+
/** Returns the GroupMembers table for the given context or the current default context. */
|
|
42
47
|
export declare function GroupMembers(dataContext?: DataContext): GroupMembersTable;
|
|
@@ -46,6 +46,7 @@ const table_1 = require("./orm/table");
|
|
|
46
46
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
47
47
|
const types_1 = require("./orm/types");
|
|
48
48
|
const users_1 = require("./users");
|
|
49
|
+
/** Schema for a signed group membership, including its role and soft deletion state. */
|
|
49
50
|
exports.groupMemberSchema = zod_1.z.object({
|
|
50
51
|
groupMemberId: zod_types_1.zodPeerId,
|
|
51
52
|
groupId: zod_types_1.zodPeerId.describe("The id of the group"),
|
|
@@ -59,6 +60,7 @@ exports.groupMemberSchema = zod_1.z.object({
|
|
|
59
60
|
.optional()
|
|
60
61
|
.describe("Whether this membership has been deleted (soft delete)"),
|
|
61
62
|
});
|
|
63
|
+
/** System table name for group membership records. */
|
|
62
64
|
exports.groupMembersTableName = "GroupMembers";
|
|
63
65
|
const metaData = {
|
|
64
66
|
name: exports.groupMembersTableName,
|
|
@@ -67,6 +69,10 @@ const metaData = {
|
|
|
67
69
|
fields: (0, types_1.schemaToFields)(exports.groupMemberSchema),
|
|
68
70
|
indexes: [{ fields: ["groupId", "userId"], unique: true }],
|
|
69
71
|
};
|
|
72
|
+
// Symbol.for keeps signer registration shared by separately installed SDK copies.
|
|
73
|
+
const signingKey = Symbol.for("@peers-app/peers-sdk/group-member-signing");
|
|
74
|
+
const signingGlobals = globalThis;
|
|
75
|
+
/** Group membership table with signature checks and signed soft deletion. */
|
|
70
76
|
let GroupMembersTable = (() => {
|
|
71
77
|
let _classSuper = table_1.Table;
|
|
72
78
|
let _instanceExtraInitializers = [];
|
|
@@ -96,10 +102,11 @@ let GroupMembersTable = (() => {
|
|
|
96
102
|
throw new Error("Group member signature is not valid");
|
|
97
103
|
}
|
|
98
104
|
async signAndSave(groupMember, opts) {
|
|
99
|
-
|
|
105
|
+
const sign = signingGlobals[signingKey];
|
|
106
|
+
if (!sign) {
|
|
100
107
|
throw new Error("Group member signing must be enabled to sign and save group members. Call GroupMembersTable.enableGroupMemberSigning(fn) to enable it.");
|
|
101
108
|
}
|
|
102
|
-
groupMember =
|
|
109
|
+
groupMember = sign.call(GroupMembersTable, groupMember);
|
|
103
110
|
return this.save(groupMember, {
|
|
104
111
|
saveAsSnapshot: true,
|
|
105
112
|
restoreIfDeleted: true,
|
|
@@ -118,9 +125,9 @@ let GroupMembersTable = (() => {
|
|
|
118
125
|
await this.signAndSave(groupMember);
|
|
119
126
|
}
|
|
120
127
|
}
|
|
121
|
-
|
|
128
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
122
129
|
static enableGroupMemberSigning(fn) {
|
|
123
|
-
|
|
130
|
+
signingGlobals[signingKey] = fn;
|
|
124
131
|
}
|
|
125
132
|
/** @deprecated Forbidden on GroupsTable; use save() */
|
|
126
133
|
insert(..._args) {
|
|
@@ -138,6 +145,7 @@ let GroupMembersTable = (() => {
|
|
|
138
145
|
})();
|
|
139
146
|
exports.GroupMembersTable = GroupMembersTable;
|
|
140
147
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.groupMemberSchema, GroupMembersTable);
|
|
148
|
+
/** Returns the GroupMembers table for the given context or the current default context. */
|
|
141
149
|
function GroupMembers(dataContext) {
|
|
142
150
|
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.groupMemberSchema, GroupMembersTable);
|
|
143
151
|
}
|
package/dist/data/groups.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { DataContext } from "../context/data-context";
|
|
|
3
3
|
import { GroupMemberRole } from "./group-member-roles";
|
|
4
4
|
import type { ISaveOptions } from "./orm/data-query";
|
|
5
5
|
import { Table } from "./orm/table";
|
|
6
|
+
/** Schema for a signed group record, including membership policy and group public keys. */
|
|
6
7
|
export declare const groupSchema: z.ZodObject<{
|
|
7
8
|
groupId: z.ZodEffects<z.ZodString, string, string>;
|
|
8
9
|
name: z.ZodString;
|
|
@@ -37,18 +38,22 @@ export declare const groupSchema: z.ZodObject<{
|
|
|
37
38
|
iconClassName?: string | undefined;
|
|
38
39
|
publicRole?: GroupMemberRole | undefined;
|
|
39
40
|
}>;
|
|
41
|
+
/** A signed group record shared between personal and group contexts. */
|
|
40
42
|
export type IGroup = z.infer<typeof groupSchema>;
|
|
43
|
+
/** System table name for group records. */
|
|
41
44
|
export declare const groupsTableName = "Groups";
|
|
45
|
+
/** Group table with signature enforcement outside the personal context. */
|
|
42
46
|
export declare class GroupsTable extends Table<IGroup> {
|
|
43
47
|
static isPassthrough: boolean;
|
|
44
48
|
save(group: IGroup, opts?: ISaveOptions): Promise<IGroup>;
|
|
45
49
|
signAndSave(group: IGroup, opts?: ISaveOptions): Promise<IGroup>;
|
|
46
50
|
delete(groupId: string): Promise<void>;
|
|
47
|
-
|
|
51
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
48
52
|
static enableGroupSigning(fn: (group: IGroup) => IGroup): void;
|
|
49
53
|
/** @deprecated Direct inserts forbidden; use save() */
|
|
50
54
|
insert(..._args: Parameters<Table<IGroup>["insert"]>): never;
|
|
51
55
|
/** @deprecated Direct updates forbidden; use save() */
|
|
52
56
|
update(..._args: Parameters<Table<IGroup>["update"]>): never;
|
|
53
57
|
}
|
|
58
|
+
/** Returns the Groups table for the given context or the current default context. */
|
|
54
59
|
export declare function Groups(dataContext?: DataContext): GroupsTable;
|
package/dist/data/groups.js
CHANGED
|
@@ -45,6 +45,7 @@ const decorators_1 = require("./orm/decorators");
|
|
|
45
45
|
const table_1 = require("./orm/table");
|
|
46
46
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
47
47
|
const types_1 = require("./orm/types");
|
|
48
|
+
/** Schema for a signed group record, including membership policy and group public keys. */
|
|
48
49
|
exports.groupSchema = zod_1.z.object({
|
|
49
50
|
groupId: zod_types_1.zodPeerId,
|
|
50
51
|
name: zod_1.z.string(),
|
|
@@ -67,6 +68,7 @@ exports.groupSchema = zod_1.z.object({
|
|
|
67
68
|
.string()
|
|
68
69
|
.describe("The public key used to encrypt data that only group members with writer permissions or higher can decrypt"),
|
|
69
70
|
});
|
|
71
|
+
/** System table name for group records. */
|
|
70
72
|
exports.groupsTableName = "Groups";
|
|
71
73
|
const metaData = {
|
|
72
74
|
name: exports.groupsTableName,
|
|
@@ -76,6 +78,10 @@ const metaData = {
|
|
|
76
78
|
iconClassName: "bi bi-people-fill",
|
|
77
79
|
indexes: [{ fields: ["name"] }],
|
|
78
80
|
};
|
|
81
|
+
// Symbol.for keeps signer registration shared by separately installed SDK copies.
|
|
82
|
+
const signingKey = Symbol.for("@peers-app/peers-sdk/group-signing");
|
|
83
|
+
const signingGlobals = globalThis;
|
|
84
|
+
/** Group table with signature enforcement outside the personal context. */
|
|
79
85
|
let GroupsTable = (() => {
|
|
80
86
|
let _classSuper = table_1.Table;
|
|
81
87
|
let _instanceExtraInitializers = [];
|
|
@@ -103,10 +109,11 @@ let GroupsTable = (() => {
|
|
|
103
109
|
return super.save(group, opts);
|
|
104
110
|
}
|
|
105
111
|
async signAndSave(group, opts) {
|
|
106
|
-
|
|
112
|
+
const sign = signingGlobals[signingKey];
|
|
113
|
+
if (!sign) {
|
|
107
114
|
throw new Error("Group signing must be enabled to sign and save groups. Call GroupsTable.enableGroupSigning(fn) to enable it.");
|
|
108
115
|
}
|
|
109
|
-
group =
|
|
116
|
+
group = sign.call(GroupsTable, group);
|
|
110
117
|
return this.save(group, opts);
|
|
111
118
|
}
|
|
112
119
|
async delete(groupId) {
|
|
@@ -117,9 +124,9 @@ let GroupsTable = (() => {
|
|
|
117
124
|
}
|
|
118
125
|
throw new Error("Only deleting groups from the user context Groups table is allowed");
|
|
119
126
|
}
|
|
120
|
-
|
|
127
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
121
128
|
static enableGroupSigning(fn) {
|
|
122
|
-
|
|
129
|
+
signingGlobals[signingKey] = fn;
|
|
123
130
|
}
|
|
124
131
|
/** @deprecated Direct inserts forbidden; use save() */
|
|
125
132
|
insert(..._args) {
|
|
@@ -137,6 +144,7 @@ let GroupsTable = (() => {
|
|
|
137
144
|
})();
|
|
138
145
|
exports.GroupsTable = GroupsTable;
|
|
139
146
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.groupSchema, GroupsTable);
|
|
147
|
+
/** Returns the Groups table for the given context or the current default context. */
|
|
140
148
|
function Groups(dataContext) {
|
|
141
149
|
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.groupSchema, GroupsTable);
|
|
142
150
|
}
|
|
@@ -107,16 +107,19 @@ declare const schema: z.ZodObject<{
|
|
|
107
107
|
uiBundleFileHash?: string | undefined;
|
|
108
108
|
packageAuthorSignature?: string | undefined;
|
|
109
109
|
}>;
|
|
110
|
+
/** A signed package build and its bundle hashes, tag, and lifecycle history. */
|
|
110
111
|
export type IPackageVersion = z.infer<typeof schema>;
|
|
112
|
+
/** Package version table with signature and group promotion permission checks. */
|
|
111
113
|
export declare class PackageVersionsTable extends Table<IPackageVersion> {
|
|
112
114
|
static isPassthrough: boolean;
|
|
113
115
|
insert(packageVersion: IPackageVersion, opts?: ISaveOptions): Promise<IPackageVersion>;
|
|
114
116
|
update(packageVersion: IPackageVersion, opts?: ISaveOptions): Promise<IPackageVersion>;
|
|
115
117
|
save(packageVersion: IPackageVersion, opts?: ISaveOptions): Promise<IPackageVersion>;
|
|
116
118
|
signAndSave(packageVersion: IPackageVersion, opts?: ISaveOptions): Promise<IPackageVersion>;
|
|
117
|
-
|
|
119
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
118
120
|
static enablePackageVersionSigning(fn: (packageVersion: IPackageVersion) => IPackageVersion): void;
|
|
119
121
|
}
|
|
122
|
+
/** Returns the PackageVersions table for the given context or the current default context. */
|
|
120
123
|
export declare function PackageVersions(dataContext?: DataContext): PackageVersionsTable;
|
|
121
124
|
/**
|
|
122
125
|
* Compute a content hash from bundle file hashes. The hash represents code
|
|
@@ -134,6 +137,7 @@ export declare function PackageVersions(dataContext?: DataContext): PackageVersi
|
|
|
134
137
|
export declare function computePackageVersionHash(version: string,
|
|
135
138
|
/** @deprecated Ignored — will be removed in a future release. */
|
|
136
139
|
_versionTag: string, packageBundleFileHash: string, routesBundleFileHash?: string, uiBundleFileHash?: string): string;
|
|
140
|
+
/** Checks whether an incoming version falls within the selected automatic update range. */
|
|
137
141
|
export declare function isVersionInRange(activeVersion: string, incomingVersion: string, range: "pinned" | "patch" | "minor" | "latest"): boolean;
|
|
138
142
|
/**
|
|
139
143
|
* Returns true if incomingVersion is strictly newer than activeVersion (semver comparison).
|
|
@@ -92,6 +92,10 @@ const metaData = {
|
|
|
92
92
|
fields: (0, types_1.schemaToFields)(schema),
|
|
93
93
|
indexes: [{ fields: ["packageId"] }],
|
|
94
94
|
};
|
|
95
|
+
// Symbol.for keeps signer registration shared by separately installed SDK copies.
|
|
96
|
+
const signingKey = Symbol.for("@peers-app/peers-sdk/package-version-signing");
|
|
97
|
+
const signingGlobals = globalThis;
|
|
98
|
+
/** Package version table with signature and group promotion permission checks. */
|
|
95
99
|
let PackageVersionsTable = (() => {
|
|
96
100
|
let _classSuper = table_1.Table;
|
|
97
101
|
let _instanceExtraInitializers = [];
|
|
@@ -122,15 +126,16 @@ let PackageVersionsTable = (() => {
|
|
|
122
126
|
return super.save(packageVersion, opts);
|
|
123
127
|
}
|
|
124
128
|
async signAndSave(packageVersion, opts) {
|
|
125
|
-
|
|
129
|
+
const sign = signingGlobals[signingKey];
|
|
130
|
+
if (!sign) {
|
|
126
131
|
throw new Error("Package version signing is not enabled. Call PackageVersionsTable.enablePackageVersionSigning(fn) to enable it.");
|
|
127
132
|
}
|
|
128
|
-
packageVersion = await
|
|
133
|
+
packageVersion = await sign.call(PackageVersionsTable, packageVersion);
|
|
129
134
|
return this.save(packageVersion, opts);
|
|
130
135
|
}
|
|
131
|
-
|
|
136
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
132
137
|
static enablePackageVersionSigning(fn) {
|
|
133
|
-
|
|
138
|
+
signingGlobals[signingKey] = fn;
|
|
134
139
|
}
|
|
135
140
|
constructor() {
|
|
136
141
|
super(...arguments);
|
|
@@ -140,6 +145,7 @@ let PackageVersionsTable = (() => {
|
|
|
140
145
|
})();
|
|
141
146
|
exports.PackageVersionsTable = PackageVersionsTable;
|
|
142
147
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, schema, PackageVersionsTable);
|
|
148
|
+
/** Returns the PackageVersions table for the given context or the current default context. */
|
|
143
149
|
function PackageVersions(dataContext) {
|
|
144
150
|
return (0, context_1.getTableContainer)(dataContext).getTable(metaData, schema, PackageVersionsTable);
|
|
145
151
|
}
|
|
@@ -161,6 +167,7 @@ function computePackageVersionHash(version,
|
|
|
161
167
|
_versionTag, packageBundleFileHash, routesBundleFileHash, uiBundleFileHash) {
|
|
162
168
|
return (0, keys_1.hashValue)([version, packageBundleFileHash, routesBundleFileHash ?? "", uiBundleFileHash ?? ""].join(":"));
|
|
163
169
|
}
|
|
170
|
+
/** Checks whether an incoming version falls within the selected automatic update range. */
|
|
164
171
|
function isVersionInRange(activeVersion, incomingVersion, range) {
|
|
165
172
|
if (range === "pinned")
|
|
166
173
|
return false;
|
package/dist/data/packages.d.ts
CHANGED
|
@@ -42,19 +42,25 @@ declare const schema: z.ZodObject<{
|
|
|
42
42
|
followVersionTags?: string | undefined;
|
|
43
43
|
updateUrl?: string | undefined;
|
|
44
44
|
}>;
|
|
45
|
+
/** A signed package record with publisher identity and version selection policy. */
|
|
45
46
|
export type IPackage = z.infer<typeof schema>;
|
|
47
|
+
/** Package table with signature enforcement outside personal contexts. */
|
|
46
48
|
export declare class PackagesTable extends Table<IPackage> {
|
|
47
49
|
static isPassthrough: boolean;
|
|
48
50
|
insert(packageObj: IPackage, opts?: ISaveOptions): Promise<IPackage>;
|
|
49
51
|
update(packageObj: IPackage, opts?: ISaveOptions): Promise<IPackage>;
|
|
50
52
|
save(packageObj: IPackage, opts?: ISaveOptions): Promise<IPackage>;
|
|
51
53
|
signAndSave(packageObj: IPackage, opts?: ISaveOptions): Promise<IPackage>;
|
|
52
|
-
|
|
54
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
53
55
|
static enablePackageSigning(fn: (packageObj: IPackage) => IPackage): void;
|
|
54
56
|
delete(packageId: string): Promise<void>;
|
|
55
57
|
}
|
|
58
|
+
/** Returns the Packages table for the given context or the current default context. */
|
|
56
59
|
export declare function Packages(dataContext?: DataContext): PackagesTable;
|
|
60
|
+
/** Default directory for locally stored package files. */
|
|
57
61
|
export declare const packagesRootDir = "~/peers/packages";
|
|
62
|
+
/** Device preference controlling package reloads when the UI refreshes. */
|
|
58
63
|
export declare const reloadPackagesOnPageRefresh: import("./persistent-vars").PersistentVar<boolean>;
|
|
64
|
+
/** Device preference enabling automatic peers-core updates. */
|
|
59
65
|
export declare const autoUpdatePeersCore: import("./persistent-vars").PersistentVar<boolean>;
|
|
60
66
|
export {};
|
package/dist/data/packages.js
CHANGED
|
@@ -83,6 +83,10 @@ const metaData = {
|
|
|
83
83
|
iconClassName: "bi bi-box-fill",
|
|
84
84
|
fields: (0, types_1.schemaToFields)(schema),
|
|
85
85
|
};
|
|
86
|
+
// Symbol.for keeps signer registration shared by separately installed SDK copies.
|
|
87
|
+
const signingKey = Symbol.for("@peers-app/peers-sdk/package-signing");
|
|
88
|
+
const signingGlobals = globalThis;
|
|
89
|
+
/** Package table with signature enforcement outside personal contexts. */
|
|
86
90
|
let PackagesTable = (() => {
|
|
87
91
|
let _classSuper = table_1.Table;
|
|
88
92
|
let _instanceExtraInitializers = [];
|
|
@@ -113,15 +117,16 @@ let PackagesTable = (() => {
|
|
|
113
117
|
return super.save(packageObj, opts);
|
|
114
118
|
}
|
|
115
119
|
async signAndSave(packageObj, opts) {
|
|
116
|
-
|
|
120
|
+
const sign = signingGlobals[signingKey];
|
|
121
|
+
if (!sign) {
|
|
117
122
|
throw new Error("Package signing is not enabled. Call PackagesTable.enablePackageSigning(fn) to enable it.");
|
|
118
123
|
}
|
|
119
|
-
packageObj = await
|
|
124
|
+
packageObj = await sign.call(PackagesTable, packageObj);
|
|
120
125
|
return this.save(packageObj, opts);
|
|
121
126
|
}
|
|
122
|
-
|
|
127
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
123
128
|
static enablePackageSigning(fn) {
|
|
124
|
-
|
|
129
|
+
signingGlobals[signingKey] = fn;
|
|
125
130
|
}
|
|
126
131
|
async delete(packageId) {
|
|
127
132
|
// anyone (with write permissions) can delete packages since that isn't a security risk (unless something else is relying on a package to be present?)
|
|
@@ -141,11 +146,15 @@ let PackagesTable = (() => {
|
|
|
141
146
|
})();
|
|
142
147
|
exports.PackagesTable = PackagesTable;
|
|
143
148
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, schema, PackagesTable);
|
|
149
|
+
/** Returns the Packages table for the given context or the current default context. */
|
|
144
150
|
function Packages(dataContext) {
|
|
145
151
|
return (0, context_1.getTableContainer)(dataContext).getTable(metaData, schema, PackagesTable);
|
|
146
152
|
}
|
|
153
|
+
/** Default directory for locally stored package files. */
|
|
147
154
|
exports.packagesRootDir = "~/peers/packages";
|
|
155
|
+
/** Device preference controlling package reloads when the UI refreshes. */
|
|
148
156
|
exports.reloadPackagesOnPageRefresh = (0, persistent_vars_1.deviceVar)("reloadPackagesOnPageRefresh", {
|
|
149
157
|
defaultValue: true,
|
|
150
158
|
});
|
|
159
|
+
/** Device preference enabling automatic peers-core updates. */
|
|
151
160
|
exports.autoUpdatePeersCore = (0, persistent_vars_1.deviceVar)("autoUpdatePeersCore", { defaultValue: true });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tableNames = ["package-version", "package", "group", "group-member", "user"];
|
|
4
|
+
// These key strings are the contract between installed SDK versions; do not rename them.
|
|
5
|
+
const signingKey = (name) => Symbol.for(`@peers-app/peers-sdk/${name}-signing`);
|
|
6
|
+
// Restore process-global registrations so these tests never leave test signers installed.
|
|
7
|
+
const priorSigners = tableNames.map((name) => {
|
|
8
|
+
const key = signingKey(name);
|
|
9
|
+
return { key, descriptor: Object.getOwnPropertyDescriptor(globalThis, key) };
|
|
10
|
+
});
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
for (const { key } of priorSigners) {
|
|
13
|
+
Reflect.deleteProperty(globalThis, key);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
for (const { key, descriptor } of priorSigners) {
|
|
18
|
+
if (descriptor) {
|
|
19
|
+
Object.defineProperty(globalThis, key, descriptor);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
Reflect.deleteProperty(globalThis, key);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
function loadSigningTables() {
|
|
27
|
+
let tables;
|
|
28
|
+
jest.isolateModules(() => {
|
|
29
|
+
const { PackageVersionsTable } = require("./package-versions");
|
|
30
|
+
const { PackagesTable } = require("./packages");
|
|
31
|
+
const { GroupsTable } = require("./groups");
|
|
32
|
+
const { GroupMembersTable } = require("./group-members");
|
|
33
|
+
const { UsersTable } = require("./users");
|
|
34
|
+
tables = {
|
|
35
|
+
"package-version": {
|
|
36
|
+
prototype: PackageVersionsTable.prototype,
|
|
37
|
+
enable: PackageVersionsTable.enablePackageVersionSigning,
|
|
38
|
+
},
|
|
39
|
+
package: { prototype: PackagesTable.prototype, enable: PackagesTable.enablePackageSigning },
|
|
40
|
+
group: { prototype: GroupsTable.prototype, enable: GroupsTable.enableGroupSigning },
|
|
41
|
+
"group-member": {
|
|
42
|
+
prototype: GroupMembersTable.prototype,
|
|
43
|
+
enable: GroupMembersTable.enableGroupMemberSigning,
|
|
44
|
+
},
|
|
45
|
+
user: { prototype: UsersTable.prototype, enable: UsersTable.enableUserSigning },
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
return tables;
|
|
49
|
+
}
|
|
50
|
+
describe("table signing across SDK module instances", () => {
|
|
51
|
+
it.each(tableNames)("shares and replaces the %s signer across copies", async (name) => {
|
|
52
|
+
const first = loadSigningTables()[name];
|
|
53
|
+
const second = loadSigningTables()[name];
|
|
54
|
+
expect(first.prototype).not.toBe(second.prototype);
|
|
55
|
+
// Stub persistence only: exercise the real signAndSave and registration methods.
|
|
56
|
+
const receiver = { save: jest.fn(async (record) => record) };
|
|
57
|
+
const row = { name: "Example", signature: "" };
|
|
58
|
+
const opts = { saveAsSnapshot: false };
|
|
59
|
+
await expect(second.prototype.signAndSave.call(receiver, row, opts)).rejects.toThrow(/signing.*enabled/i);
|
|
60
|
+
expect(receiver.save).not.toHaveBeenCalled();
|
|
61
|
+
const sign = jest.fn((record) => ({ ...record, signature: "first" }));
|
|
62
|
+
first.enable(sign);
|
|
63
|
+
expect(Reflect.get(globalThis, signingKey(name))).toBe(sign);
|
|
64
|
+
await expect(second.prototype.signAndSave.call(receiver, row, opts)).resolves.toEqual({
|
|
65
|
+
...row,
|
|
66
|
+
signature: "first",
|
|
67
|
+
});
|
|
68
|
+
expect(sign).toHaveBeenCalledWith(row);
|
|
69
|
+
expect(sign.mock.contexts.at(-1)).toBe(second.prototype.constructor);
|
|
70
|
+
expect(receiver.save).toHaveBeenLastCalledWith({ ...row, signature: "first" }, name === "group-member" ? { ...opts, restoreIfDeleted: true } : opts);
|
|
71
|
+
// Loading another copy must preserve a signer that is already registered.
|
|
72
|
+
const third = loadSigningTables()[name];
|
|
73
|
+
expect(third.prototype).not.toBe(first.prototype);
|
|
74
|
+
await expect(third.prototype.signAndSave.call(receiver, row)).resolves.toEqual({
|
|
75
|
+
...row,
|
|
76
|
+
signature: "first",
|
|
77
|
+
});
|
|
78
|
+
expect(sign.mock.contexts.at(-1)).toBe(third.prototype.constructor);
|
|
79
|
+
second.enable((record) => ({ ...record, signature: "replacement" }));
|
|
80
|
+
for (const copy of [first, third]) {
|
|
81
|
+
await expect(copy.prototype.signAndSave.call(receiver, row)).resolves.toEqual({
|
|
82
|
+
...row,
|
|
83
|
+
signature: "replacement",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
receiver.save.mockClear();
|
|
87
|
+
const failsOnce = jest
|
|
88
|
+
.fn((record) => ({ ...record, signature: "recovered" }))
|
|
89
|
+
.mockImplementationOnce(() => {
|
|
90
|
+
throw new Error("signing failed");
|
|
91
|
+
});
|
|
92
|
+
first.enable(failsOnce);
|
|
93
|
+
await expect(second.prototype.signAndSave.call(receiver, row)).rejects.toThrow("signing failed");
|
|
94
|
+
expect(receiver.save).not.toHaveBeenCalled();
|
|
95
|
+
await expect(third.prototype.signAndSave.call(receiver, row)).resolves.toEqual({
|
|
96
|
+
...row,
|
|
97
|
+
signature: "recovered",
|
|
98
|
+
});
|
|
99
|
+
expect(failsOnce).toHaveBeenCalledTimes(2);
|
|
100
|
+
receiver.save.mockRejectedValueOnce(new Error("save failed"));
|
|
101
|
+
await expect(second.prototype.signAndSave.call(receiver, row)).rejects.toThrow("save failed");
|
|
102
|
+
await expect(first.prototype.signAndSave.call(receiver, row)).resolves.toEqual({
|
|
103
|
+
...row,
|
|
104
|
+
signature: "recovered",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
it("keeps the five signer registrations independent", async () => {
|
|
108
|
+
const first = loadSigningTables();
|
|
109
|
+
const second = loadSigningTables();
|
|
110
|
+
for (const name of tableNames) {
|
|
111
|
+
first[name].enable((record) => ({ ...record, signature: name }));
|
|
112
|
+
}
|
|
113
|
+
const receiver = { save: jest.fn(async (record) => record) };
|
|
114
|
+
for (const name of tableNames) {
|
|
115
|
+
await expect(second[name].prototype.signAndSave.call(receiver, { name: "Example", signature: "" })).resolves.toEqual({ name: "Example", signature: name });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
package/dist/data/users.d.ts
CHANGED
|
@@ -84,8 +84,7 @@ export declare class UsersTable extends Table<IUser> {
|
|
|
84
84
|
*/
|
|
85
85
|
save(user: IUser, opts?: ISaveOptions): Promise<IUser>;
|
|
86
86
|
signAndSave(user: IUser, opts?: ISaveOptions): Promise<IUser>;
|
|
87
|
-
|
|
88
|
-
/** Enables signing for proxied `signAndSave` calls. */
|
|
87
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
89
88
|
static enableUserSigning(fn: (user: IUser) => IUser): void;
|
|
90
89
|
/** @deprecated Forbidden on UsersTable; use save() */
|
|
91
90
|
insert(..._args: Parameters<Table<IUser>["insert"]>): never;
|
package/dist/data/users.js
CHANGED
|
@@ -102,6 +102,9 @@ let userRowChangeGuard = refuseIdentityChanges;
|
|
|
102
102
|
function setUserRowChangeGuard(guard) {
|
|
103
103
|
userRowChangeGuard = guard ?? refuseIdentityChanges;
|
|
104
104
|
}
|
|
105
|
+
// Symbol.for keeps signer registration shared by separately installed SDK copies.
|
|
106
|
+
const signingKey = Symbol.for("@peers-app/peers-sdk/user-signing");
|
|
107
|
+
const signingGlobals = globalThis;
|
|
105
108
|
/** User table with owner-signature enforcement outside the personal context. */
|
|
106
109
|
let UsersTable = (() => {
|
|
107
110
|
let _classSuper = table_1.Table;
|
|
@@ -170,20 +173,20 @@ let UsersTable = (() => {
|
|
|
170
173
|
return super.save(verdict.row, opts);
|
|
171
174
|
}
|
|
172
175
|
async signAndSave(user, opts) {
|
|
173
|
-
|
|
176
|
+
const sign = signingGlobals[signingKey];
|
|
177
|
+
if (!sign) {
|
|
174
178
|
throw new Error("User signing must be enabled to sign and save users. Call UsersTable.enableUserSigning(fn) to enable it.");
|
|
175
179
|
}
|
|
176
180
|
user = {
|
|
177
181
|
...user,
|
|
178
182
|
name: user.name.slice(0, devices_1.DISPLAY_NAME_MAX_LENGTH),
|
|
179
183
|
};
|
|
180
|
-
user =
|
|
184
|
+
user = sign.call(UsersTable, user);
|
|
181
185
|
return this.save(user, opts);
|
|
182
186
|
}
|
|
183
|
-
|
|
184
|
-
/** Enables signing for proxied `signAndSave` calls. */
|
|
187
|
+
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
185
188
|
static enableUserSigning(fn) {
|
|
186
|
-
|
|
189
|
+
signingGlobals[signingKey] = fn;
|
|
187
190
|
}
|
|
188
191
|
/** @deprecated Forbidden on UsersTable; use save() */
|
|
189
192
|
insert(..._args) {
|