@peers-app/peers-sdk 0.28.2 → 0.28.4
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/context/user-context-singleton.js +2 -0
- package/dist/contracts/contract-proxy.d.ts +1 -1
- package/dist/contracts/contract-proxy.js +3 -1
- package/dist/data/group-members.js +2 -1
- package/dist/data/group-resign.js +4 -1
- package/dist/data/groups.js +2 -1
- package/dist/data/orm/client-proxy.data-source.d.ts +1 -0
- package/dist/data/orm/client-proxy.data-source.js +3 -0
- package/dist/data/orm/data-query.d.ts +20 -0
- package/dist/data/orm/data-query.js +5 -0
- package/dist/data/orm/decorators.d.ts +2 -0
- package/dist/data/orm/decorators.js +11 -0
- package/dist/data/orm/write-checks.d.ts +6 -4
- package/dist/data/orm/write-checks.js +12 -5
- package/dist/data/package-versions.js +6 -1
- package/dist/data/packages.js +2 -1
- package/dist/data/table-definitions-table.d.ts +3 -3
- package/dist/data/tool-access-approvals.d.ts +3 -3
- package/dist/package-loader/isolated-runtime.d.ts +18 -2
- package/dist/package-loader/isolated-runtime.js +26 -5
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ exports.getTableContainer = getTableContainer;
|
|
|
9
9
|
exports.setDefaultClientUserContext = setDefaultClientUserContext;
|
|
10
10
|
exports.getAllTables = getAllTables;
|
|
11
11
|
const client_proxy_data_source_1 = require("../data/orm/client-proxy.data-source");
|
|
12
|
+
const decorators_1 = require("../data/orm/decorators");
|
|
12
13
|
const rpc_types_1 = require("../rpc-types");
|
|
13
14
|
const utils_1 = require("../utils");
|
|
14
15
|
const user_context_1 = require("./user-context");
|
|
@@ -170,6 +171,7 @@ if (!rpc_types_1.isClient) {
|
|
|
170
171
|
if (typeof method !== "function") {
|
|
171
172
|
throw new Error(`Method ${methodName} not found on table ${tableName}`);
|
|
172
173
|
}
|
|
174
|
+
(0, decorators_1.checkRemoteTableSaveOptions)(methodName, args);
|
|
173
175
|
// @ts-expect-error - call this way to ensure 'this' is correct
|
|
174
176
|
return table[methodName](...args);
|
|
175
177
|
};
|
|
@@ -3,7 +3,7 @@ import type { Table } from "../data/orm/table";
|
|
|
3
3
|
import type { ITool, IToolInstance } from "../data/tools";
|
|
4
4
|
import type { Event, ISubscriptionResult } from "../events";
|
|
5
5
|
import { type Observable } from "../observable";
|
|
6
|
-
import type
|
|
6
|
+
import { type IIsolatedCallPrincipal } from "../package-loader/isolated-runtime";
|
|
7
7
|
import type { IWorkflowRunContext } from "../types/workflow-run-context";
|
|
8
8
|
import { type IContractTransport } from "./contract-transport";
|
|
9
9
|
import type { IContractDefinition, IRemoteContractConsumer } from "./types";
|
|
@@ -12,6 +12,7 @@ const access_level_1 = require("../data/access-level");
|
|
|
12
12
|
const group_permissions_1 = require("../data/group-permissions");
|
|
13
13
|
const decorators_1 = require("../data/orm/decorators");
|
|
14
14
|
const observable_1 = require("../observable");
|
|
15
|
+
const isolated_runtime_1 = require("../package-loader/isolated-runtime");
|
|
15
16
|
const utils_1 = require("../utils");
|
|
16
17
|
const action_dispatch_1 = require("./action-dispatch");
|
|
17
18
|
const contract_transport_1 = require("./contract-transport");
|
|
@@ -584,7 +585,8 @@ function createContractProvider(resolution, opts = {}) {
|
|
|
584
585
|
!(0, decorators_1.isContractRemoteTableMethod)(method)) {
|
|
585
586
|
throw new Error(`Table method '${call.name}.${call.operation}' is not remotely callable`);
|
|
586
587
|
}
|
|
587
|
-
|
|
588
|
+
(0, decorators_1.checkRemoteTableSaveOptions)(call.operation, call.args);
|
|
589
|
+
return impl.apply(table, (0, isolated_runtime_1.isolatedTableArgs)(call.operation, call.args));
|
|
588
590
|
}
|
|
589
591
|
case "tool": {
|
|
590
592
|
if (call.operation !== "run") {
|
|
@@ -131,9 +131,10 @@ let GroupMembersTable = (() => {
|
|
|
131
131
|
...(await (0, write_checks_1.signingStamp)(this, groupMember, current)),
|
|
132
132
|
});
|
|
133
133
|
return this.save(groupMember, {
|
|
134
|
-
saveAsSnapshot: true,
|
|
135
134
|
restoreIfDeleted: true,
|
|
136
135
|
...(opts || {}),
|
|
136
|
+
saveAsSnapshot: true,
|
|
137
|
+
writtenAt: groupMember.signedAt,
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
async delete(groupMemberId) {
|
|
@@ -39,7 +39,10 @@ async function resignGroupAuthority(dataContext, opts = {}) {
|
|
|
39
39
|
try {
|
|
40
40
|
if (opts.secretKey) {
|
|
41
41
|
const stamp = await (0, write_checks_1.signingStamp)(table, row, row);
|
|
42
|
-
await table.save((0, keys_1.addSignatureToObject)({ ...row, ...stamp }, opts.secretKey),
|
|
42
|
+
await table.save((0, keys_1.addSignatureToObject)({ ...row, ...stamp }, opts.secretKey), {
|
|
43
|
+
...snapshot,
|
|
44
|
+
writtenAt: stamp.signedAt,
|
|
45
|
+
});
|
|
43
46
|
}
|
|
44
47
|
else {
|
|
45
48
|
await table.signAndSave(prepare(row), snapshot);
|
package/dist/data/groups.js
CHANGED
|
@@ -116,7 +116,8 @@ let GroupsTable = (() => {
|
|
|
116
116
|
...group,
|
|
117
117
|
...(await (0, write_checks_1.signingStamp)(this, group)),
|
|
118
118
|
});
|
|
119
|
-
|
|
119
|
+
// Field patches from concurrent writes could combine into a row nobody signed.
|
|
120
|
+
return this.save(group, { ...opts, saveAsSnapshot: true, writtenAt: group.signedAt });
|
|
120
121
|
}
|
|
121
122
|
/**
|
|
122
123
|
* Re-sign this group's authority rows (group row, memberships, packages, package versions)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
import { type DataFilter, type ICursorIterable, type IDataQueryParams, type IDataSource, type ISaveOptions } from "./data-query";
|
|
3
3
|
import { type ITableMetaData } from "./types";
|
|
4
|
+
/** A renderer's table data source, forwarding operations to the host over RPC. */
|
|
4
5
|
export declare class ClientProxyDataSource<T extends {
|
|
5
6
|
[key: string]: any;
|
|
6
7
|
}> implements IDataSource<T> {
|
|
@@ -4,7 +4,9 @@ exports.ClientProxyDataSource = void 0;
|
|
|
4
4
|
const rpc_types_1 = require("../../rpc-types");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
6
|
const data_query_1 = require("./data-query");
|
|
7
|
+
const decorators_1 = require("./decorators");
|
|
7
8
|
const types_1 = require("./types");
|
|
9
|
+
/** A renderer's table data source, forwarding operations to the host over RPC. */
|
|
8
10
|
class ClientProxyDataSource {
|
|
9
11
|
metaData;
|
|
10
12
|
schema;
|
|
@@ -38,6 +40,7 @@ class ClientProxyDataSource {
|
|
|
38
40
|
return rpc_types_1.rpcServerCalls.tableMethodCall(this.dataContextId, this.tableName, "findOne", filter, opts);
|
|
39
41
|
}
|
|
40
42
|
async save(record, opts) {
|
|
43
|
+
(0, decorators_1.checkRemoteTableSaveOptions)("save", [record, opts]);
|
|
41
44
|
return rpc_types_1.rpcServerCalls.tableMethodCall(this.dataContextId, this.tableName, "save", record, opts);
|
|
42
45
|
}
|
|
43
46
|
async insert(record) {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
/** Options controlling how a host table save is recorded. */
|
|
1
2
|
export interface ISaveOptions {
|
|
2
3
|
restoreIfDeleted?: boolean;
|
|
4
|
+
/** @internal Host-only change time for signed rows; must match their signedAt. */
|
|
5
|
+
writtenAt?: number;
|
|
3
6
|
saveAsSnapshot?: boolean;
|
|
4
7
|
weakInsert?: boolean;
|
|
5
8
|
insertOnly?: boolean;
|
|
6
9
|
}
|
|
10
|
+
/** Persistence operations for one table. */
|
|
7
11
|
export interface IDataSource<T extends {
|
|
8
12
|
[key: string]: any;
|
|
9
13
|
}> {
|
|
@@ -18,6 +22,7 @@ export interface IDataSource<T extends {
|
|
|
18
22
|
update: (record: T) => Promise<T>;
|
|
19
23
|
delete: (data: string | T) => Promise<void>;
|
|
20
24
|
}
|
|
25
|
+
/** Table operations needed to execute a data query. */
|
|
21
26
|
export interface ITable<T extends Record<string, any>> {
|
|
22
27
|
tableName: string;
|
|
23
28
|
metaData: {
|
|
@@ -34,6 +39,7 @@ export interface ITable<T extends Record<string, any>> {
|
|
|
34
39
|
textSearch?: string;
|
|
35
40
|
}) => Promise<T[]>;
|
|
36
41
|
}
|
|
42
|
+
/** Filtering, ordering and pagination for table reads. */
|
|
37
43
|
export interface IDataQueryParams<T extends Record<string, any>> {
|
|
38
44
|
page?: number;
|
|
39
45
|
pageSize?: number;
|
|
@@ -43,6 +49,7 @@ export interface IDataQueryParams<T extends Record<string, any>> {
|
|
|
43
49
|
textSearchExact?: boolean;
|
|
44
50
|
skipPast?: T;
|
|
45
51
|
}
|
|
52
|
+
/** A table query that can be listed or consumed through a cursor. */
|
|
46
53
|
export declare class DataQuery<T extends Record<string, any>> {
|
|
47
54
|
readonly table: ITable<T>;
|
|
48
55
|
constructor(table: ITable<T>, { page, pageSize, sortBy, filter, textSearch, textSearchExact }?: IDataQueryParams<T>);
|
|
@@ -55,18 +62,23 @@ export declare class DataQuery<T extends Record<string, any>> {
|
|
|
55
62
|
cursor(): ICursorIterable<T>;
|
|
56
63
|
list(): Promise<T[]>;
|
|
57
64
|
}
|
|
65
|
+
/** A cursor positioned at a row, with optional seek support. */
|
|
58
66
|
export interface ICursor<T> {
|
|
59
67
|
value: T | null;
|
|
60
68
|
next: (skipPast?: T) => Promise<T | null>;
|
|
61
69
|
}
|
|
70
|
+
/** A cursor that also supports asynchronous iteration. */
|
|
62
71
|
export type ICursorIterable<T> = ICursor<T> & AsyncIterable<T>;
|
|
72
|
+
/** Adds asynchronous iteration to a cursor. */
|
|
63
73
|
export declare function iterableCursor<T>(cursor: ICursor<T>): ICursorIterable<T>;
|
|
74
|
+
/** Reads a data source in pages through an asynchronous cursor. */
|
|
64
75
|
export declare function dataSourceCursor<T extends {
|
|
65
76
|
[key: string]: any;
|
|
66
77
|
}>(dataSource: {
|
|
67
78
|
list: (filter?: DataFilter<T>, opts?: IDataQueryParams<T>) => Promise<T[]>;
|
|
68
79
|
primaryKeyName: string;
|
|
69
80
|
}, filter?: DataFilter<T>, opts?: IDataQueryParams<T>): ICursorIterable<T>;
|
|
81
|
+
/** Counts matching rows, falling back to a cursor when native count is unavailable. */
|
|
70
82
|
export declare function dataSourceCount<T extends {
|
|
71
83
|
[key: string]: any;
|
|
72
84
|
}>(dataSource: {
|
|
@@ -74,11 +86,15 @@ export declare function dataSourceCount<T extends {
|
|
|
74
86
|
list: (filter?: DataFilter<T>, opts?: IDataQueryParams<T>) => Promise<T[]>;
|
|
75
87
|
primaryKeyName: string;
|
|
76
88
|
}, filter?: DataFilter<T>): Promise<number>;
|
|
89
|
+
/** Ordered fields; a leading minus selects descending order. */
|
|
77
90
|
export type SortBy<T extends {
|
|
78
91
|
[key: string]: any;
|
|
79
92
|
}> = (keyof T extends string | number ? keyof T | `-${keyof T}` : never)[];
|
|
93
|
+
/** Scalar values accepted by data filters. */
|
|
80
94
|
export type DataFieldScalar = boolean | number | string | Date | null;
|
|
95
|
+
/** Comparison operators accepted in a field filter. */
|
|
81
96
|
export type DataFilterValueOperator = "$eq" | "$ne" | "$gt" | "$gte" | "$lt" | "$lte" | "$exists" | "$matchWords" | "$substr" | "$expr" | "$in";
|
|
97
|
+
/** A field value or comparison used in a data filter. */
|
|
82
98
|
export type DataFilterValue = DataFieldScalar | DataFieldScalar[] | {
|
|
83
99
|
[key in Exclude<DataFilterValueOperator, "$in">]?: DataFieldScalar;
|
|
84
100
|
} | {
|
|
@@ -86,13 +102,17 @@ export type DataFilterValue = DataFieldScalar | DataFieldScalar[] | {
|
|
|
86
102
|
} | {
|
|
87
103
|
$in: DataFieldScalar[];
|
|
88
104
|
};
|
|
105
|
+
/** Field predicates combined with AND. */
|
|
89
106
|
export type DataFilterAnd<T> = {
|
|
90
107
|
[key in keyof T]?: DataFilterValue;
|
|
91
108
|
};
|
|
109
|
+
/** Alternative groups of field predicates combined with OR. */
|
|
92
110
|
export type DataFilterOr<T> = DataFilterAnd<T>[] | {
|
|
93
111
|
$or: DataFilterAnd<T>[];
|
|
94
112
|
};
|
|
113
|
+
/** A table filter composed of field predicates and logical groups. */
|
|
95
114
|
export type DataFilter<T> = DataFilterAnd<T> | DataFilterOr<T> | {
|
|
96
115
|
$and: DataFilter<T>[];
|
|
97
116
|
};
|
|
117
|
+
/** Adds predicates to resume an ordered query after the supplied row. */
|
|
98
118
|
export declare function filterToSkipPastValue(filter: DataFilter<unknown>, sortBy: string[], skipPast: any): DataFilter<unknown>;
|
|
@@ -5,6 +5,7 @@ exports.iterableCursor = iterableCursor;
|
|
|
5
5
|
exports.dataSourceCursor = dataSourceCursor;
|
|
6
6
|
exports.dataSourceCount = dataSourceCount;
|
|
7
7
|
exports.filterToSkipPastValue = filterToSkipPastValue;
|
|
8
|
+
/** A table query that can be listed or consumed through a cursor. */
|
|
8
9
|
class DataQuery {
|
|
9
10
|
table;
|
|
10
11
|
constructor(table, { page, pageSize, sortBy, filter, textSearch, textSearchExact } = {}) {
|
|
@@ -85,6 +86,7 @@ class DataQuery {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
exports.DataQuery = DataQuery;
|
|
89
|
+
/** Adds asynchronous iteration to a cursor. */
|
|
88
90
|
function iterableCursor(cursor) {
|
|
89
91
|
// @ts-expect-error - we're explicitly extending the cursor object to have this symbol
|
|
90
92
|
cursor[Symbol.asyncIterator] = () => {
|
|
@@ -97,6 +99,7 @@ function iterableCursor(cursor) {
|
|
|
97
99
|
};
|
|
98
100
|
return cursor;
|
|
99
101
|
}
|
|
102
|
+
/** Reads a data source in pages through an asynchronous cursor. */
|
|
100
103
|
function dataSourceCursor(dataSource, filter = {}, opts = {}) {
|
|
101
104
|
// if (dataSource.cursor) {
|
|
102
105
|
// return dataSource.cursor(filter, opts);
|
|
@@ -157,6 +160,7 @@ function dataSourceCursor(dataSource, filter = {}, opts = {}) {
|
|
|
157
160
|
};
|
|
158
161
|
return iterableCursor(cursor);
|
|
159
162
|
}
|
|
163
|
+
/** Counts matching rows, falling back to a cursor when native count is unavailable. */
|
|
160
164
|
async function dataSourceCount(dataSource, filter = {}) {
|
|
161
165
|
if (dataSource.count) {
|
|
162
166
|
return dataSource.count(filter);
|
|
@@ -169,6 +173,7 @@ async function dataSourceCount(dataSource, filter = {}) {
|
|
|
169
173
|
}
|
|
170
174
|
return count;
|
|
171
175
|
}
|
|
176
|
+
/** Adds predicates to resume an ordered query after the supplied row. */
|
|
172
177
|
function filterToSkipPastValue(filter, sortBy, skipPast) {
|
|
173
178
|
const sortByFilters = [];
|
|
174
179
|
for (let i = 0; i < sortBy.length; i++) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Refuse host-only signed write times supplied through a table RPC or contract call. */
|
|
2
|
+
export declare function checkRemoteTableSaveOptions(methodName: string, args: readonly unknown[]): void;
|
|
1
3
|
/**
|
|
2
4
|
* Return whether a table method was explicitly marked for remote invocation by
|
|
3
5
|
* {@link ProxyClientTableMethodCalls}. Client proxies are recognized through their
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkRemoteTableSaveOptions = checkRemoteTableSaveOptions;
|
|
3
4
|
exports.isContractRemoteTableMethod = isContractRemoteTableMethod;
|
|
4
5
|
exports.ProxyClientTableMethodCalls = ProxyClientTableMethodCalls;
|
|
5
6
|
const rpc_types_1 = require("../../rpc-types");
|
|
6
7
|
const contractRemoteTableMethod = Symbol("contractRemoteTableMethod");
|
|
8
|
+
/** Refuse host-only signed write times supplied through a table RPC or contract call. */
|
|
9
|
+
function checkRemoteTableSaveOptions(methodName, args) {
|
|
10
|
+
if (!["save", "insert", "update", "signAndSave"].includes(methodName))
|
|
11
|
+
return;
|
|
12
|
+
const options = args[1];
|
|
13
|
+
if (options && typeof options === "object" && "writtenAt" in options) {
|
|
14
|
+
throw new Error("writtenAt is host-only; use signAndSave to sign a new change");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
7
17
|
function markContractRemoteTableMethod(method) {
|
|
8
18
|
Object.defineProperty(method, contractRemoteTableMethod, { value: true });
|
|
9
19
|
}
|
|
@@ -37,6 +47,7 @@ function ProxyClientTableMethodCalls() {
|
|
|
37
47
|
const methodName = context.name;
|
|
38
48
|
// WARNING: Using typescript's magical `this` param
|
|
39
49
|
const proxyFn = function (...args) {
|
|
50
|
+
checkRemoteTableSaveOptions(methodName, args);
|
|
40
51
|
const dataContextId = this.dataSource.dataContextId || this.groupId || "";
|
|
41
52
|
return rpc_types_1.rpcServerCalls.tableMethodCall(dataContextId, this.tableName, methodName, ...args);
|
|
42
53
|
};
|
|
@@ -57,10 +57,12 @@ export declare function checkLocalSave<T extends {
|
|
|
57
57
|
*/
|
|
58
58
|
export declare const packageApprovalTables: ReadonlySet<string>;
|
|
59
59
|
/**
|
|
60
|
-
* What a table's `signAndSave` (and a re-sign) puts under the signature: `signedAt`,
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
60
|
+
* What a table's `signAndSave` (and a re-sign) puts under the signature: `signedAt`, a tick of
|
|
61
|
+
* the context's write clock (wall time without a tracked source) or just after the row on record
|
|
62
|
+
* when that was signed by a clock running ahead, so the new signature counts as the later one
|
|
63
|
+
* (and, for a package table, after the deleted row's retained stamp); for a package table also
|
|
64
|
+
* the context the approval is for. The save then records the change at this same time
|
|
65
|
+
* (`writtenAt`), so sync and the signed order agree on which concurrent write is later.
|
|
64
66
|
*
|
|
65
67
|
* @param table - The table being signed for.
|
|
66
68
|
* @param row - The row being signed.
|
|
@@ -56,10 +56,12 @@ async function checkLocalSave(table, row, check) {
|
|
|
56
56
|
*/
|
|
57
57
|
exports.packageApprovalTables = new Set(["Packages", "PackageVersions"]);
|
|
58
58
|
/**
|
|
59
|
-
* What a table's `signAndSave` (and a re-sign) puts under the signature: `signedAt`,
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
59
|
+
* What a table's `signAndSave` (and a re-sign) puts under the signature: `signedAt`, a tick of
|
|
60
|
+
* the context's write clock (wall time without a tracked source) or just after the row on record
|
|
61
|
+
* when that was signed by a clock running ahead, so the new signature counts as the later one
|
|
62
|
+
* (and, for a package table, after the deleted row's retained stamp); for a package table also
|
|
63
|
+
* the context the approval is for. The save then records the change at this same time
|
|
64
|
+
* (`writtenAt`), so sync and the signed order agree on which concurrent write is later.
|
|
63
65
|
*
|
|
64
66
|
* @param table - The table being signed for.
|
|
65
67
|
* @param row - The row being signed.
|
|
@@ -76,8 +78,13 @@ async function signingStamp(table, row, current) {
|
|
|
76
78
|
const dataContext = (await getUserContext()).getDataContext(groupId);
|
|
77
79
|
floor = await deletedSignedAt(tableName, { dataContext, recordId });
|
|
78
80
|
}
|
|
81
|
+
// Duck typing also works when the data source comes from another installed SDK copy.
|
|
82
|
+
let source = table.dataSource;
|
|
83
|
+
while (source && !source.getWriteClock)
|
|
84
|
+
source = source.dataSource;
|
|
85
|
+
const clock = await source?.getWriteClock?.();
|
|
79
86
|
return {
|
|
80
|
-
signedAt: Math.max(Date.now(), floor + 1),
|
|
87
|
+
signedAt: Math.max(clock ? Math.ceil(clock.tick()) : Date.now(), floor + 1),
|
|
81
88
|
...(packageTable ? { signedContextId: groupId } : {}),
|
|
82
89
|
};
|
|
83
90
|
}
|
|
@@ -137,7 +137,12 @@ let PackageVersionsTable = (() => {
|
|
|
137
137
|
...packageVersion,
|
|
138
138
|
...(await (0, write_checks_1.signingStamp)(this, packageVersion)),
|
|
139
139
|
});
|
|
140
|
-
|
|
140
|
+
// Field patches from concurrent writes could combine into a row nobody signed.
|
|
141
|
+
return this.save(packageVersion, {
|
|
142
|
+
...opts,
|
|
143
|
+
saveAsSnapshot: true,
|
|
144
|
+
writtenAt: packageVersion.signedAt,
|
|
145
|
+
});
|
|
141
146
|
}
|
|
142
147
|
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
143
148
|
static enablePackageVersionSigning(fn) {
|
package/dist/data/packages.js
CHANGED
|
@@ -127,7 +127,8 @@ let PackagesTable = (() => {
|
|
|
127
127
|
...packageObj,
|
|
128
128
|
...(await (0, write_checks_1.signingStamp)(this, packageObj)),
|
|
129
129
|
});
|
|
130
|
-
|
|
130
|
+
// Field patches from concurrent writes could combine into a row nobody signed.
|
|
131
|
+
return this.save(packageObj, { ...opts, saveAsSnapshot: true, writtenAt: packageObj.signedAt });
|
|
131
132
|
}
|
|
132
133
|
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
133
134
|
static enablePackageSigning(fn) {
|
|
@@ -9,18 +9,18 @@ export declare const tableDefinitionRecordSchema: z.ZodObject<{
|
|
|
9
9
|
deleted: z.ZodOptional<z.ZodDate>;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
name: string;
|
|
12
|
+
tableId: string;
|
|
12
13
|
metaData: {} & {
|
|
13
14
|
[k: string]: any;
|
|
14
15
|
};
|
|
15
|
-
tableId: string;
|
|
16
16
|
versionNumber: number;
|
|
17
17
|
deleted?: Date | undefined;
|
|
18
18
|
}, {
|
|
19
19
|
name: string;
|
|
20
|
+
tableId: string;
|
|
20
21
|
metaData: {} & {
|
|
21
22
|
[k: string]: any;
|
|
22
23
|
};
|
|
23
|
-
tableId: string;
|
|
24
24
|
deleted?: Date | undefined;
|
|
25
25
|
versionNumber?: number | undefined;
|
|
26
26
|
}>;
|
|
@@ -36,10 +36,10 @@ export type ITableDefinitionRecord = z.infer<typeof tableDefinitionRecordSchema>
|
|
|
36
36
|
*/
|
|
37
37
|
export declare function TableDefinitions(dataContext?: DataContext): import("..").Table<{
|
|
38
38
|
name: string;
|
|
39
|
+
tableId: string;
|
|
39
40
|
metaData: {} & {
|
|
40
41
|
[k: string]: any;
|
|
41
42
|
};
|
|
42
|
-
tableId: string;
|
|
43
43
|
versionNumber: number;
|
|
44
44
|
deleted?: Date | undefined;
|
|
45
45
|
}>;
|
|
@@ -46,9 +46,9 @@ export declare const toolAccessApprovalSchema: z.ZodObject<{
|
|
|
46
46
|
}, "strip", z.ZodTypeAny, {
|
|
47
47
|
nonce: string;
|
|
48
48
|
status: ToolAccessApprovalStatus;
|
|
49
|
-
userId: string;
|
|
50
49
|
toolName: string;
|
|
51
50
|
toolId: string;
|
|
51
|
+
userId: string;
|
|
52
52
|
scope: ToolAccessApprovalScope;
|
|
53
53
|
createdAt: Date;
|
|
54
54
|
dataContextId: string;
|
|
@@ -69,9 +69,9 @@ export declare const toolAccessApprovalSchema: z.ZodObject<{
|
|
|
69
69
|
resultSummary?: string | undefined;
|
|
70
70
|
}, {
|
|
71
71
|
nonce: string;
|
|
72
|
-
userId: string;
|
|
73
72
|
toolName: string;
|
|
74
73
|
toolId: string;
|
|
74
|
+
userId: string;
|
|
75
75
|
dataContextId: string;
|
|
76
76
|
expiresAt: Date;
|
|
77
77
|
toolAccessApprovalId: string;
|
|
@@ -102,9 +102,9 @@ export type IToolAccessApproval = z.infer<typeof toolAccessApprovalSchema>;
|
|
|
102
102
|
export declare function ToolAccessApprovals(dataContext?: DataContext): import("..").Table<{
|
|
103
103
|
nonce: string;
|
|
104
104
|
status: ToolAccessApprovalStatus;
|
|
105
|
-
userId: string;
|
|
106
105
|
toolName: string;
|
|
107
106
|
toolId: string;
|
|
107
|
+
userId: string;
|
|
108
108
|
scope: ToolAccessApprovalScope;
|
|
109
109
|
createdAt: Date;
|
|
110
110
|
dataContextId: string;
|
|
@@ -12,17 +12,33 @@ export declare const ISOLATED_CONTRACT_TABLE_OPERATIONS: readonly ["get", "list"
|
|
|
12
12
|
export type IsolatedContractTableOperation = (typeof ISOLATED_CONTRACT_TABLE_OPERATIONS)[number];
|
|
13
13
|
/** Options a package may pass with a table `save`. */
|
|
14
14
|
export interface IPackageSaveOptions {
|
|
15
|
+
/** Seed a new row so any real write wins, even one not yet synced. Has no effect on updates. */
|
|
16
|
+
weakInsert?: boolean;
|
|
17
|
+
/** Create if missing; otherwise leave the row untouched and return it. Use with weakInsert for defaults. */
|
|
18
|
+
insertOnly?: boolean;
|
|
19
|
+
/** Reset the whole row, replacing even unseen earlier edits from other devices. Later writes still win. */
|
|
20
|
+
saveAsSnapshot?: boolean;
|
|
15
21
|
/** Save a row whose id was deleted before. Without it, that save is refused. */
|
|
16
22
|
restoreIfDeleted?: boolean;
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
25
|
+
* Copy every host save option except `writtenAt`, accepting only values exactly equal to `true`.
|
|
26
|
+
* `writtenAt` stays host-only: it orders signed rows by their signing time, and accepting it
|
|
27
|
+
* from a package would let that package backdate writes. Unknown keys are dropped.
|
|
21
28
|
*
|
|
22
29
|
* @param options - A table `save`'s second argument, as received.
|
|
23
30
|
* @returns The allowed options, or `undefined` when none are set.
|
|
24
31
|
*/
|
|
25
32
|
export declare function isolatedSaveOptions(options: unknown): IPackageSaveOptions | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Limit a package or contract table write to its public arguments. Only `save` accepts
|
|
35
|
+
* options; `insert` and `update` accept only a row. Other operations keep their arguments.
|
|
36
|
+
*
|
|
37
|
+
* @param operation - The table method being called.
|
|
38
|
+
* @param args - Its arguments, as received across the bridge.
|
|
39
|
+
* @returns Arguments with save options filtered by {@link isolatedSaveOptions}.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isolatedTableArgs(operation: string, args: unknown[]): unknown[];
|
|
26
42
|
/** One line a package worker wrote to its stdout or stderr. */
|
|
27
43
|
export interface IIsolatedWorkerOutput {
|
|
28
44
|
/** The worker's package. */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ISOLATED_CONTRACT_TABLE_EVENTS = exports.ISOLATED_CONTRACT_TABLE_OPERATIONS = void 0;
|
|
4
4
|
exports.isolatedSaveOptions = isolatedSaveOptions;
|
|
5
|
+
exports.isolatedTableArgs = isolatedTableArgs;
|
|
5
6
|
exports.setIsolatedPackageRuntimeFactory = setIsolatedPackageRuntimeFactory;
|
|
6
7
|
exports.getIsolatedPackageRuntimeFactory = getIsolatedPackageRuntimeFactory;
|
|
7
8
|
/** Standard table methods exposed through isolated contract-table references. */
|
|
@@ -16,16 +17,36 @@ exports.ISOLATED_CONTRACT_TABLE_OPERATIONS = [
|
|
|
16
17
|
"delete",
|
|
17
18
|
];
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* Copy every host save option except `writtenAt`, accepting only values exactly equal to `true`.
|
|
21
|
+
* `writtenAt` stays host-only: it orders signed rows by their signing time, and accepting it
|
|
22
|
+
* from a package would let that package backdate writes. Unknown keys are dropped.
|
|
21
23
|
*
|
|
22
24
|
* @param options - A table `save`'s second argument, as received.
|
|
23
25
|
* @returns The allowed options, or `undefined` when none are set.
|
|
24
26
|
*/
|
|
25
27
|
function isolatedSaveOptions(options) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const supplied = options;
|
|
29
|
+
const allowed = {};
|
|
30
|
+
for (const key of ["weakInsert", "insertOnly", "saveAsSnapshot", "restoreIfDeleted"]) {
|
|
31
|
+
if (supplied?.[key] === true)
|
|
32
|
+
allowed[key] = true;
|
|
33
|
+
}
|
|
34
|
+
return Object.keys(allowed).length ? allowed : undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Limit a package or contract table write to its public arguments. Only `save` accepts
|
|
38
|
+
* options; `insert` and `update` accept only a row. Other operations keep their arguments.
|
|
39
|
+
*
|
|
40
|
+
* @param operation - The table method being called.
|
|
41
|
+
* @param args - Its arguments, as received across the bridge.
|
|
42
|
+
* @returns Arguments with save options filtered by {@link isolatedSaveOptions}.
|
|
43
|
+
*/
|
|
44
|
+
function isolatedTableArgs(operation, args) {
|
|
45
|
+
if (operation === "save") {
|
|
46
|
+
const options = isolatedSaveOptions(args[1]);
|
|
47
|
+
return options ? [args[0], options] : args.slice(0, 1);
|
|
48
|
+
}
|
|
49
|
+
return operation === "insert" || operation === "update" ? args.slice(0, 1) : args;
|
|
29
50
|
}
|
|
30
51
|
/** Table events consumers may subscribe to on an isolated contract table. */
|
|
31
52
|
exports.ISOLATED_CONTRACT_TABLE_EVENTS = ["dataChanged"];
|