@peers-app/peers-sdk 0.25.8 → 0.25.10
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/contracts/__tests__/contract-proxy.test.js +72 -0
- package/dist/contracts/contract-proxy.d.ts +34 -1
- package/dist/contracts/contract-proxy.js +56 -21
- package/dist/contracts/contract-resolvers.js +1 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +11 -1
- package/dist/contracts/system/local-folders-contract.d.ts +163 -0
- package/dist/contracts/system/local-folders-contract.js +235 -0
- package/dist/contracts/system/network-contracts.d.ts +81 -1
- package/dist/contracts/system/network-contracts.js +55 -2
- package/dist/data/change-tracking.d.ts +5 -0
- package/dist/data/change-tracking.js +18 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/local-folders.d.ts +176 -0
- package/dist/data/local-folders.js +116 -0
- package/dist/data/orm/sql-db.d.ts +3 -1
- package/dist/data/orm/table.d.ts +19 -0
- package/dist/data/orm/table.js +18 -0
- package/dist/data/persistent-vars.conflict.test.d.ts +1 -0
- package/dist/data/persistent-vars.conflict.test.js +126 -0
- package/dist/data/persistent-vars.d.ts +13 -0
- package/dist/data/persistent-vars.js +53 -0
- package/dist/data/sync-recovery-queue.d.ts +77 -0
- package/dist/data/sync-recovery-queue.js +128 -1
- package/dist/data/sync-recovery-queue.test.js +78 -1
- package/dist/rpc-types.d.ts +0 -3
- package/dist/rpc-types.js +0 -3
- package/dist/system-ids.d.ts +22 -0
- package/dist/system-ids.js +23 -1
- package/package.json +1 -1
|
@@ -426,6 +426,32 @@ describe("contract proxy — error handling", () => {
|
|
|
426
426
|
const consumer = consumerVia(contract, provider);
|
|
427
427
|
await expect(consumer.tables.Widgets.list()).rejects.toThrow(/does not provide table 'Widgets'/);
|
|
428
428
|
});
|
|
429
|
+
it("forwards callerPackageId when the resolution opts into call context", async () => {
|
|
430
|
+
const seen = [];
|
|
431
|
+
const provider = (0, contract_proxy_1.createContractProvider)({
|
|
432
|
+
contractId: CONTRACT_ID,
|
|
433
|
+
version: 1,
|
|
434
|
+
forwardCallContext: true,
|
|
435
|
+
tools: {
|
|
436
|
+
listGrants: {
|
|
437
|
+
tool: { toolId: (0, utils_1.newid)(), name: "listGrants", accessLevel: 0 },
|
|
438
|
+
toolFn: async (host) => {
|
|
439
|
+
seen.push(host.callerPackageId ?? null);
|
|
440
|
+
return "ok";
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
await provider({
|
|
446
|
+
contractId: CONTRACT_ID,
|
|
447
|
+
version: 1,
|
|
448
|
+
member: "tool",
|
|
449
|
+
name: "listGrants",
|
|
450
|
+
operation: "run",
|
|
451
|
+
args: [],
|
|
452
|
+
}, { callerPackageId: "00pkg00000000000000000001" });
|
|
453
|
+
expect(seen).toEqual(["00pkg00000000000000000001"]);
|
|
454
|
+
});
|
|
429
455
|
it.each([
|
|
430
456
|
["tool", "missingTool"],
|
|
431
457
|
["observable", "missingObservable"],
|
|
@@ -520,6 +546,52 @@ describe("contract proxy — permission checks", () => {
|
|
|
520
546
|
expect(denied.table.save).not.toHaveBeenCalled();
|
|
521
547
|
});
|
|
522
548
|
});
|
|
549
|
+
describe("contract provider endpoint event filter", () => {
|
|
550
|
+
it("delivers a generic event only to subscribers the filter allows", async () => {
|
|
551
|
+
const handlers = new Set();
|
|
552
|
+
const changed = {
|
|
553
|
+
eventName: () => "changed",
|
|
554
|
+
subscribe: (handler) => {
|
|
555
|
+
handlers.add(handler);
|
|
556
|
+
return {
|
|
557
|
+
unsubscribe: () => {
|
|
558
|
+
handlers.delete(handler);
|
|
559
|
+
return true;
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
const resolution = {
|
|
565
|
+
contractId: CONTRACT_ID,
|
|
566
|
+
version: 1,
|
|
567
|
+
events: { changed: changed },
|
|
568
|
+
eventFilter: (_eventName, payload, context) => payload.owner === context.callerPackageId,
|
|
569
|
+
};
|
|
570
|
+
const delivered = [];
|
|
571
|
+
const endpoint = (0, contract_proxy_1.createContractProviderEndpoint)(resolution, {
|
|
572
|
+
notify: async (notification) => {
|
|
573
|
+
delivered.push(notification.subscriptionId);
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
const subscribe = (subscriptionId, callerPackageId) => endpoint.handleCall({
|
|
577
|
+
contractId: CONTRACT_ID,
|
|
578
|
+
version: 1,
|
|
579
|
+
member: "event",
|
|
580
|
+
name: "changed",
|
|
581
|
+
operation: "subscribe",
|
|
582
|
+
subscriptionId,
|
|
583
|
+
args: [],
|
|
584
|
+
}, { callerPackageId });
|
|
585
|
+
await subscribe("allowed", "pkg-a");
|
|
586
|
+
await subscribe("denied", "pkg-b");
|
|
587
|
+
for (const handler of handlers) {
|
|
588
|
+
handler({ owner: "pkg-a" });
|
|
589
|
+
}
|
|
590
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
591
|
+
expect(delivered).toEqual(["allowed"]);
|
|
592
|
+
endpoint.dispose();
|
|
593
|
+
});
|
|
594
|
+
});
|
|
523
595
|
describe("connectionContractTransport", () => {
|
|
524
596
|
it("emits on the request channel with the call and returns the response", async () => {
|
|
525
597
|
const emit = jest.fn(async (_event, _call) => ["ok"]);
|
|
@@ -220,6 +220,11 @@ export interface IContractToolContext {
|
|
|
220
220
|
* by the host and returned only to the provider-side tool implementation.
|
|
221
221
|
*/
|
|
222
222
|
getVariable(variableName: string, requestingToolId: string): Promise<string>;
|
|
223
|
+
/**
|
|
224
|
+
* Isolated package that originated this call, when the host runtime supplied one.
|
|
225
|
+
* Absent for trusted local callers (the signed-in UI session and the CLI).
|
|
226
|
+
*/
|
|
227
|
+
callerPackageId?: string;
|
|
223
228
|
}
|
|
224
229
|
/**
|
|
225
230
|
* Build the **consumer** side of a contract proxy from a contract definition and a
|
|
@@ -293,6 +298,13 @@ export interface IContractResolution {
|
|
|
293
298
|
* Omit this for remote or otherwise untrusted provider routes.
|
|
294
299
|
*/
|
|
295
300
|
toolContext?: IContractToolContext;
|
|
301
|
+
/**
|
|
302
|
+
* When true, provider tool functions receive an {@link IContractToolContext} as their
|
|
303
|
+
* final argument even if {@link toolContext} was not set, including
|
|
304
|
+
* {@link IContractToolContext.callerPackageId} from the current call. Host contracts
|
|
305
|
+
* that authorize by calling package set this.
|
|
306
|
+
*/
|
|
307
|
+
forwardCallContext?: boolean;
|
|
296
308
|
observables?: Record<string, Observable<any>>;
|
|
297
309
|
/**
|
|
298
310
|
* Provider-owned write policy for live observables. A `set` is allowed only when the
|
|
@@ -306,6 +318,20 @@ export interface IContractResolution {
|
|
|
306
318
|
* their payloads to its configured notification sink.
|
|
307
319
|
*/
|
|
308
320
|
events?: Record<string, Event<any>>;
|
|
321
|
+
/**
|
|
322
|
+
* Optional per-subscriber gate for generic contract events.
|
|
323
|
+
*
|
|
324
|
+
* Table and observable streams are not filtered. The endpoint invokes this once
|
|
325
|
+
* per subscriber with the {@link IContractCallContext} captured at subscribe time.
|
|
326
|
+
* Return false, or reject, to drop that notification for that subscriber only.
|
|
327
|
+
* A shared endpoint can therefore hide one caller's events from another.
|
|
328
|
+
*
|
|
329
|
+
* @param eventName Contract event name, such as `changed`.
|
|
330
|
+
* @param payload Payload about to be delivered.
|
|
331
|
+
* @param context Caller identity from the subscribe call.
|
|
332
|
+
* @returns Whether this subscriber may receive the payload.
|
|
333
|
+
*/
|
|
334
|
+
eventFilter?: (eventName: string, payload: unknown, context: IContractCallContext) => boolean | Promise<boolean>;
|
|
309
335
|
}
|
|
310
336
|
/** Identity of the caller, supplied by the transport layer for permission checks. */
|
|
311
337
|
export interface IContractCallContext {
|
|
@@ -319,6 +345,11 @@ export interface IContractCallContext {
|
|
|
319
345
|
* host router before dispatch.
|
|
320
346
|
*/
|
|
321
347
|
callerDeviceId?: string;
|
|
348
|
+
/**
|
|
349
|
+
* Isolated package that originated this call. Set by the isolate runtime from host
|
|
350
|
+
* state, never from a guest payload. Absent for trusted local UI and CLI callers.
|
|
351
|
+
*/
|
|
352
|
+
callerPackageId?: string;
|
|
322
353
|
/**
|
|
323
354
|
* Provider-side data context used to resolve the caller's group/personal role.
|
|
324
355
|
* In-process only — never serialized across a connection.
|
|
@@ -418,7 +449,9 @@ export interface IContractProviderEndpoint {
|
|
|
418
449
|
* or an {@link Observable} (`resolution.observables[name]`) — is only subscribed to while at
|
|
419
450
|
* least one consumer holds a subscription (refcounted by a resolved key), and each payload is
|
|
420
451
|
* fanned out through the supplied {@link ContractNotificationSink} as an
|
|
421
|
-
* {@link IContractNotification}.
|
|
452
|
+
* {@link IContractNotification}. Generic events pass through
|
|
453
|
+
* {@link IContractResolution.eventFilter} once per subscriber, using the caller context
|
|
454
|
+
* captured when that subscriber subscribed. The endpoint owns no request listener, which lets a
|
|
422
455
|
* connection-wide router multiplex many endpoints through one request channel and later
|
|
423
456
|
* substitute sandbox-backed endpoint implementations.
|
|
424
457
|
*
|
|
@@ -534,9 +534,19 @@ function createContractProvider(resolution, opts = {}) {
|
|
|
534
534
|
throw new Error(`Contract ${call.contractId} does not provide tool '${call.name}'`);
|
|
535
535
|
}
|
|
536
536
|
await assertContractToolAccess(tool, call, context);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
537
|
+
if (resolution.toolContext || resolution.forwardCallContext) {
|
|
538
|
+
const base = resolution.toolContext ?? {
|
|
539
|
+
dataContextId: context.dataContext?.dataContextId ?? "",
|
|
540
|
+
getVariable: async () => {
|
|
541
|
+
throw new Error("Persistent variables are not available to this contract tool");
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
return tool.toolFn(...call.args, {
|
|
545
|
+
...base,
|
|
546
|
+
callerPackageId: context.callerPackageId,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
return tool.toolFn(...call.args);
|
|
540
550
|
}
|
|
541
551
|
case "observable": {
|
|
542
552
|
const obs = resolution.observables?.[call.name];
|
|
@@ -571,7 +581,9 @@ function createContractProvider(resolution, opts = {}) {
|
|
|
571
581
|
* or an {@link Observable} (`resolution.observables[name]`) — is only subscribed to while at
|
|
572
582
|
* least one consumer holds a subscription (refcounted by a resolved key), and each payload is
|
|
573
583
|
* fanned out through the supplied {@link ContractNotificationSink} as an
|
|
574
|
-
* {@link IContractNotification}.
|
|
584
|
+
* {@link IContractNotification}. Generic events pass through
|
|
585
|
+
* {@link IContractResolution.eventFilter} once per subscriber, using the caller context
|
|
586
|
+
* captured when that subscriber subscribed. The endpoint owns no request listener, which lets a
|
|
575
587
|
* connection-wide router multiplex many endpoints through one request channel and later
|
|
576
588
|
* substitute sandbox-backed endpoint implementations.
|
|
577
589
|
*
|
|
@@ -581,9 +593,10 @@ function createContractProvider(resolution, opts = {}) {
|
|
|
581
593
|
function createContractProviderEndpoint(resolution, opts) {
|
|
582
594
|
const { notify, permissionCheck, context: defaultContext } = opts;
|
|
583
595
|
const dispatch = createContractProvider(resolution, { permissionCheck });
|
|
584
|
-
// One live subscription per resolved subscription key, refcounted by the
|
|
585
|
-
//
|
|
586
|
-
//
|
|
596
|
+
// One live subscription per resolved subscription key, refcounted by the subscribers
|
|
597
|
+
// currently attached to it, plus a reverse index for unsubscribe. Each subscriber keeps
|
|
598
|
+
// the caller context from its subscribe call so event filters can differ per consumer.
|
|
599
|
+
// Keys namespace generic events (`event:<name>`), table events
|
|
587
600
|
// (`table:<name>:<event>`), and observable streams (`observable:<name>`) so the same
|
|
588
601
|
// machinery serves all three.
|
|
589
602
|
const byKey = new Map();
|
|
@@ -651,29 +664,51 @@ function createContractProviderEndpoint(resolution, opts) {
|
|
|
651
664
|
},
|
|
652
665
|
};
|
|
653
666
|
};
|
|
654
|
-
const
|
|
667
|
+
const reportNotifyFailure = (subscriptionId, err) => {
|
|
668
|
+
console.error(`Contract notify failed for subscription '${subscriptionId}'`, err);
|
|
669
|
+
};
|
|
670
|
+
const deliver = (key, subscriptionId, payload, context) => {
|
|
671
|
+
// Start each notification independently. A slow or rejected destination must not
|
|
672
|
+
// block sibling subscribers, and every rejection is handled because Observable
|
|
673
|
+
// callbacks do not await returned promises. Without a filter, attach the catch
|
|
674
|
+
// directly so a rejected notify is logged on the same turn as before.
|
|
675
|
+
if (!(key.startsWith("event:") && resolution.eventFilter)) {
|
|
676
|
+
if (!subIdToKey.has(subscriptionId)) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
void notifySink(subscriptionId, payload, key).catch((err) => {
|
|
680
|
+
reportNotifyFailure(subscriptionId, err);
|
|
681
|
+
});
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
void (async () => {
|
|
685
|
+
const allowed = await resolution.eventFilter?.(key.slice("event:".length), payload, context);
|
|
686
|
+
if (!allowed || !subIdToKey.has(subscriptionId)) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
await notifySink(subscriptionId, payload, key);
|
|
690
|
+
})().catch((err) => {
|
|
691
|
+
reportNotifyFailure(subscriptionId, err);
|
|
692
|
+
});
|
|
693
|
+
};
|
|
694
|
+
const subscribe = (key, attach, subscriptionId, context) => {
|
|
655
695
|
if (subIdToKey.has(subscriptionId)) {
|
|
656
696
|
throw new Error(`Duplicate contract subscriptionId '${subscriptionId}'`);
|
|
657
697
|
}
|
|
658
698
|
let entry = byKey.get(key);
|
|
659
699
|
if (!entry) {
|
|
660
700
|
// First subscriber for this key: attach the single live subscription.
|
|
661
|
-
const
|
|
701
|
+
const subscribers = new Map();
|
|
662
702
|
const detach = attach((payload) => {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
// callbacks do not await returned promises.
|
|
666
|
-
for (const sid of [...subIds]) {
|
|
667
|
-
void notifySink(sid, payload, key).catch((err) => {
|
|
668
|
-
console.error(`Contract notify failed for subscription '${sid}'`, err);
|
|
669
|
-
});
|
|
703
|
+
for (const [sid, subscriberContext] of [...subscribers]) {
|
|
704
|
+
deliver(key, sid, payload, subscriberContext);
|
|
670
705
|
}
|
|
671
706
|
});
|
|
672
|
-
entry = { liveUnsub: detach,
|
|
707
|
+
entry = { liveUnsub: detach, subscribers };
|
|
673
708
|
byKey.set(key, entry);
|
|
674
709
|
}
|
|
675
710
|
subIdToKey.set(subscriptionId, key);
|
|
676
|
-
entry.
|
|
711
|
+
entry.subscribers.set(subscriptionId, context);
|
|
677
712
|
};
|
|
678
713
|
const unsubscribe = (subscriptionId) => {
|
|
679
714
|
const key = subIdToKey.get(subscriptionId);
|
|
@@ -685,8 +720,8 @@ function createContractProviderEndpoint(resolution, opts) {
|
|
|
685
720
|
if (!entry) {
|
|
686
721
|
return;
|
|
687
722
|
}
|
|
688
|
-
entry.
|
|
689
|
-
if (entry.
|
|
723
|
+
entry.subscribers.delete(subscriptionId);
|
|
724
|
+
if (entry.subscribers.size === 0) {
|
|
690
725
|
// Last subscriber left: detach the live subscription (nothing more is pushed).
|
|
691
726
|
entry.liveUnsub();
|
|
692
727
|
byKey.delete(key);
|
|
@@ -731,7 +766,7 @@ function createContractProviderEndpoint(resolution, opts) {
|
|
|
731
766
|
throw new Error(`Contract provider endpoint ${resolution.contractId} v${resolution.version} is disposed`);
|
|
732
767
|
}
|
|
733
768
|
const { key, attach } = resolveSubscription(call);
|
|
734
|
-
subscribe(key, attach, call.subscriptionId);
|
|
769
|
+
subscribe(key, attach, call.subscriptionId, context);
|
|
735
770
|
}
|
|
736
771
|
finally {
|
|
737
772
|
pendingSubIds.delete(call.subscriptionId);
|
|
@@ -149,6 +149,7 @@ const permissionDenied = (call, reason) => new Error(`Permission denied: ${call.
|
|
|
149
149
|
const localOnlyContractIds = new Set([
|
|
150
150
|
system_ids_1.identityContractId,
|
|
151
151
|
system_ids_1.invitesContractId,
|
|
152
|
+
system_ids_1.localFoldersContractId,
|
|
152
153
|
system_ids_1.toolAccessControlContractId,
|
|
153
154
|
]);
|
|
154
155
|
/**
|
|
@@ -15,6 +15,7 @@ export { createRemoteContractEndpoint, getRemoteContractTransportFactory, type I
|
|
|
15
15
|
export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./system/device-operations-contract";
|
|
16
16
|
export { getIdentityContractDefinition, IDENTITY_CONTRACT_VERSION, type IIdentityConsumer, type IIdentitySessionInfo, } from "./system/identity-contract";
|
|
17
17
|
export { getInvitesContractDefinition, type IAcceptInviteResult, type ICreatedInvite, type IInvitePreview, type IInvitesConsumer, INVITES_CONTRACT_VERSION, } from "./system/invites-contract";
|
|
18
|
+
export { getLocalFoldersContractDefinition, type ILocalFolderChange, type ILocalFolderChangedEvent, type ILocalFolderEntry, type ILocalFolderFileBlocks, type ILocalFolderFileBlocksInput, type ILocalFolderGrantInfo, type ILocalFolderIndexInput, type ILocalFolderJobFinishedEvent, type ILocalFolderJobHandle, type ILocalFolderJobInfo, type ILocalFolderJobProgressEvent, type ILocalFolderListInput, type ILocalFolderMoveInput, type ILocalFolderPathInput, type ILocalFolderPurgeTrashInput, type ILocalFolderReadRangeInput, type ILocalFolderReadRangeResult, type ILocalFolderRequestGrantInput, type ILocalFolderStatInput, LOCAL_FOLDERS_CHUNK_AVG, LOCAL_FOLDERS_CHUNK_MAX, LOCAL_FOLDERS_CHUNK_MIN, LOCAL_FOLDERS_CONTRACT_VERSION, LOCAL_FOLDERS_JOB_TTL_MS, LOCAL_FOLDERS_READ_RANGE_MAX, LOCAL_FOLDERS_RESERVED_DIR, type LocalFolderChangeKind, type LocalFolderEntryKind, type LocalFolderMode, localFoldersProviderPackageId, } from "./system/local-folders-contract";
|
|
18
19
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
|
|
19
20
|
export * from "./system/network-contracts";
|
|
20
21
|
export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./system/tool-access-control-contract";
|
package/dist/contracts/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = exports.setRemoteContractTransportFactory = exports.resolveRemoteTargetEndpoint = exports.getRemoteContractTransportFactory = exports.createRemoteContractEndpoint = exports.ContractRegistry = exports.PersistentContractRegistry = exports.waitForHostContractTransport = exports.subscribeHostContractTransport = exports.registerHostContractTransport = exports.getHostContractTransport = exports.hostContractConsumer = exports.setSchemaToFieldsFn = exports.extractToolShape = exports.extractTableShape = exports.createLocalContractConsumer = exports.contractsSchema = exports.contractsMetaData = exports.ContractsTable = exports.Contracts = exports.inProcessTransportPair = exports.connectionContractTransport = exports.CONTRACT_REQUEST_CHANNEL = exports.CONTRACT_NOTIFY_CHANNEL = exports.verifyRemoteContractIdentity = exports.registerContractResolver = exports.isSelfTrustedContractCaller = exports.handleContractCall = exports.getContractResolver = exports.createUserContextContractProviderRouter = exports.createLocalUserContextContractProviderRouter = exports.authorizeRemoteContractCall = exports.sameUserContractPermissionCheck = exports.createRemoteContractConsumer = exports.createContractProviderSession = exports.createContractProviderEndpoint = exports.createContractProvider = exports.createContractConsumer = exports.CONTRACT_CALL_RPC = exports.contractProvidersSchema = exports.contractProvidersMetaData = exports.ContractProvidersTable = exports.ContractProviders = exports.createContractProviderRouter = exports.PackageBuilder = exports.definePackage = exports.ContractBuilder = void 0;
|
|
18
|
-
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.INVITES_CONTRACT_VERSION = exports.getInvitesContractDefinition = exports.IDENTITY_CONTRACT_VERSION = exports.getIdentityContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = void 0;
|
|
18
|
+
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.localFoldersProviderPackageId = exports.LOCAL_FOLDERS_RESERVED_DIR = exports.LOCAL_FOLDERS_READ_RANGE_MAX = exports.LOCAL_FOLDERS_JOB_TTL_MS = exports.LOCAL_FOLDERS_CONTRACT_VERSION = exports.LOCAL_FOLDERS_CHUNK_MIN = exports.LOCAL_FOLDERS_CHUNK_MAX = exports.LOCAL_FOLDERS_CHUNK_AVG = exports.getLocalFoldersContractDefinition = exports.INVITES_CONTRACT_VERSION = exports.getInvitesContractDefinition = exports.IDENTITY_CONTRACT_VERSION = exports.getIdentityContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = void 0;
|
|
19
19
|
var builder_1 = require("./builder");
|
|
20
20
|
Object.defineProperty(exports, "ContractBuilder", { enumerable: true, get: function () { return builder_1.ContractBuilder; } });
|
|
21
21
|
Object.defineProperty(exports, "definePackage", { enumerable: true, get: function () { return builder_1.definePackage; } });
|
|
@@ -91,6 +91,16 @@ Object.defineProperty(exports, "IDENTITY_CONTRACT_VERSION", { enumerable: true,
|
|
|
91
91
|
var invites_contract_1 = require("./system/invites-contract");
|
|
92
92
|
Object.defineProperty(exports, "getInvitesContractDefinition", { enumerable: true, get: function () { return invites_contract_1.getInvitesContractDefinition; } });
|
|
93
93
|
Object.defineProperty(exports, "INVITES_CONTRACT_VERSION", { enumerable: true, get: function () { return invites_contract_1.INVITES_CONTRACT_VERSION; } });
|
|
94
|
+
var local_folders_contract_1 = require("./system/local-folders-contract");
|
|
95
|
+
Object.defineProperty(exports, "getLocalFoldersContractDefinition", { enumerable: true, get: function () { return local_folders_contract_1.getLocalFoldersContractDefinition; } });
|
|
96
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_CHUNK_AVG", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_CHUNK_AVG; } });
|
|
97
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_CHUNK_MAX", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_CHUNK_MAX; } });
|
|
98
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_CHUNK_MIN", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_CHUNK_MIN; } });
|
|
99
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_CONTRACT_VERSION", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_CONTRACT_VERSION; } });
|
|
100
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_JOB_TTL_MS", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_JOB_TTL_MS; } });
|
|
101
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_READ_RANGE_MAX", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_READ_RANGE_MAX; } });
|
|
102
|
+
Object.defineProperty(exports, "LOCAL_FOLDERS_RESERVED_DIR", { enumerable: true, get: function () { return local_folders_contract_1.LOCAL_FOLDERS_RESERVED_DIR; } });
|
|
103
|
+
Object.defineProperty(exports, "localFoldersProviderPackageId", { enumerable: true, get: function () { return local_folders_contract_1.localFoldersProviderPackageId; } });
|
|
94
104
|
var logs_contract_1 = require("./system/logs-contract");
|
|
95
105
|
Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true, get: function () { return logs_contract_1.getLogsContractDefinition; } });
|
|
96
106
|
Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { IContractDefinition } from "../types";
|
|
2
|
+
/** Version of the built-in System Local Folders contract. */
|
|
3
|
+
export declare const LOCAL_FOLDERS_CONTRACT_VERSION = 1;
|
|
4
|
+
/** Maximum byte length accepted by `readRange` in one call. */
|
|
5
|
+
export declare const LOCAL_FOLDERS_READ_RANGE_MAX: number;
|
|
6
|
+
/** FastCDC minimum block size. Files at or below this size are one block. */
|
|
7
|
+
export declare const LOCAL_FOLDERS_CHUNK_MIN: number;
|
|
8
|
+
/** FastCDC target average block size. */
|
|
9
|
+
export declare const LOCAL_FOLDERS_CHUNK_AVG: number;
|
|
10
|
+
/** FastCDC maximum block size. */
|
|
11
|
+
export declare const LOCAL_FOLDERS_CHUNK_MAX: number;
|
|
12
|
+
/** Directory name reserved inside every grant for trash and in-flight files. */
|
|
13
|
+
export declare const LOCAL_FOLDERS_RESERVED_DIR = ".peers";
|
|
14
|
+
/** How long finished index jobs stay readable via `getJob`. */
|
|
15
|
+
export declare const LOCAL_FOLDERS_JOB_TTL_MS: number;
|
|
16
|
+
/** Package ID used by live System Local Folders tool instances. */
|
|
17
|
+
export declare const localFoldersProviderPackageId = "000peers0system0000000001";
|
|
18
|
+
/** Grant mode accepted by `requestGrant`. */
|
|
19
|
+
export type LocalFolderMode = "read" | "readwrite";
|
|
20
|
+
/** Filesystem entry kind returned by `list` and `stat`. */
|
|
21
|
+
export type LocalFolderEntryKind = "file" | "dir" | "symlink";
|
|
22
|
+
/** Watcher change kind delivered on the `changed` event. */
|
|
23
|
+
export type LocalFolderChangeKind = "created" | "modified" | "deleted" | "renamed";
|
|
24
|
+
/** Input for {@link ILocalFoldersConsumer tools.requestGrant}. */
|
|
25
|
+
export interface ILocalFolderRequestGrantInput {
|
|
26
|
+
groupId: string;
|
|
27
|
+
mode: LocalFolderMode;
|
|
28
|
+
/** Operator-only. Ignored when an isolated package is the caller. */
|
|
29
|
+
packageId?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Operator-only absolute path. Isolated callers cannot set this.
|
|
32
|
+
* Omit it on a desktop host to open the folder picker.
|
|
33
|
+
*/
|
|
34
|
+
absolutePath?: string;
|
|
35
|
+
}
|
|
36
|
+
/** One active grant returned by `requestGrant` and `listGrants`. */
|
|
37
|
+
export interface ILocalFolderGrantInfo {
|
|
38
|
+
grantId: string;
|
|
39
|
+
groupId: string;
|
|
40
|
+
absolutePath: string;
|
|
41
|
+
mode: LocalFolderMode;
|
|
42
|
+
packageId?: string;
|
|
43
|
+
createdAt: number;
|
|
44
|
+
}
|
|
45
|
+
/** Input for listing a directory inside a grant. */
|
|
46
|
+
export interface ILocalFolderListInput {
|
|
47
|
+
grantId: string;
|
|
48
|
+
/** Relative path. Empty lists the grant root. */
|
|
49
|
+
relPath?: string;
|
|
50
|
+
recursive?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** One directory entry. */
|
|
53
|
+
export interface ILocalFolderEntry {
|
|
54
|
+
relPath: string;
|
|
55
|
+
name: string;
|
|
56
|
+
kind: LocalFolderEntryKind;
|
|
57
|
+
size: number;
|
|
58
|
+
mtimeMs: number;
|
|
59
|
+
inode: string;
|
|
60
|
+
}
|
|
61
|
+
/** Input for `stat`. */
|
|
62
|
+
export interface ILocalFolderStatInput {
|
|
63
|
+
grantId: string;
|
|
64
|
+
relPath: string;
|
|
65
|
+
}
|
|
66
|
+
/** Input for a bounded read. `length` is capped at {@link LOCAL_FOLDERS_READ_RANGE_MAX}. */
|
|
67
|
+
export interface ILocalFolderReadRangeInput {
|
|
68
|
+
grantId: string;
|
|
69
|
+
relPath: string;
|
|
70
|
+
offset: number;
|
|
71
|
+
length: number;
|
|
72
|
+
}
|
|
73
|
+
/** Bytes returned by `readRange`. `data` is a base64 string so it survives JSON tool results. */
|
|
74
|
+
export interface ILocalFolderReadRangeResult {
|
|
75
|
+
dataBase64: string;
|
|
76
|
+
bytesRead: number;
|
|
77
|
+
}
|
|
78
|
+
/** Input for starting an index job. */
|
|
79
|
+
export interface ILocalFolderIndexInput {
|
|
80
|
+
grantId: string;
|
|
81
|
+
/** Relative directory or file. Empty indexes the whole grant. */
|
|
82
|
+
relPath?: string;
|
|
83
|
+
}
|
|
84
|
+
/** Handle returned by `index`. */
|
|
85
|
+
export interface ILocalFolderJobHandle {
|
|
86
|
+
jobId: string;
|
|
87
|
+
}
|
|
88
|
+
/** Input for `getFileBlocks`. */
|
|
89
|
+
export interface ILocalFolderFileBlocksInput {
|
|
90
|
+
grantId: string;
|
|
91
|
+
/** Relative file path. */
|
|
92
|
+
relPath: string;
|
|
93
|
+
}
|
|
94
|
+
/** Indexed blocks for one file. `indexed` is false when the path has no index row. */
|
|
95
|
+
export interface ILocalFolderFileBlocks {
|
|
96
|
+
indexed: boolean;
|
|
97
|
+
size?: number;
|
|
98
|
+
mtimeMs?: number;
|
|
99
|
+
blocks: {
|
|
100
|
+
hash: string;
|
|
101
|
+
size: number;
|
|
102
|
+
}[];
|
|
103
|
+
}
|
|
104
|
+
/** Index job snapshot returned by `getJob`. */
|
|
105
|
+
export interface ILocalFolderJobInfo {
|
|
106
|
+
jobId: string;
|
|
107
|
+
kind: "index";
|
|
108
|
+
status: "running" | "done" | "error" | "cancelled";
|
|
109
|
+
done: number;
|
|
110
|
+
total: number;
|
|
111
|
+
error?: string;
|
|
112
|
+
result?: {
|
|
113
|
+
files: number;
|
|
114
|
+
rehashed: number;
|
|
115
|
+
skipped: number;
|
|
116
|
+
removed: number;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Input for `move`. */
|
|
120
|
+
export interface ILocalFolderMoveInput {
|
|
121
|
+
grantId: string;
|
|
122
|
+
from: string;
|
|
123
|
+
to: string;
|
|
124
|
+
}
|
|
125
|
+
/** Input for `trash` and single-path tools. */
|
|
126
|
+
export interface ILocalFolderPathInput {
|
|
127
|
+
grantId: string;
|
|
128
|
+
relPath: string;
|
|
129
|
+
}
|
|
130
|
+
/** Input for `purgeTrash`. */
|
|
131
|
+
export interface ILocalFolderPurgeTrashInput {
|
|
132
|
+
grantId: string;
|
|
133
|
+
olderThanDays: number;
|
|
134
|
+
}
|
|
135
|
+
/** One path change inside a grant. */
|
|
136
|
+
export interface ILocalFolderChange {
|
|
137
|
+
relPath: string;
|
|
138
|
+
kind: LocalFolderChangeKind;
|
|
139
|
+
}
|
|
140
|
+
/** Payload of the `changed` event. */
|
|
141
|
+
export interface ILocalFolderChangedEvent {
|
|
142
|
+
grantId: string;
|
|
143
|
+
changes: ILocalFolderChange[];
|
|
144
|
+
}
|
|
145
|
+
/** Payload of the `jobProgress` event. */
|
|
146
|
+
export interface ILocalFolderJobProgressEvent {
|
|
147
|
+
jobId: string;
|
|
148
|
+
done: number;
|
|
149
|
+
total: number;
|
|
150
|
+
}
|
|
151
|
+
/** Payload of the `jobFinished` event. */
|
|
152
|
+
export interface ILocalFolderJobFinishedEvent {
|
|
153
|
+
jobId: string;
|
|
154
|
+
status: "done" | "error" | "cancelled";
|
|
155
|
+
error?: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Return the local-only System Local Folders contract shape.
|
|
159
|
+
*
|
|
160
|
+
* The host checks every path against an operator grant. Remote devices cannot call
|
|
161
|
+
* this contract; bytes between devices move through block exchange, not these tools.
|
|
162
|
+
*/
|
|
163
|
+
export declare function getLocalFoldersContractDefinition(): IContractDefinition;
|