@openlfcp/client 0.1.4 → 0.2.0-beta.1
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/README.md +2 -2
- package/dist/access-recovery.d.ts +69 -0
- package/dist/access-recovery.js +45 -0
- package/dist/batch-status.d.ts +104 -0
- package/dist/batch-status.js +171 -0
- package/dist/claim-journal.d.ts +54 -0
- package/dist/claim-journal.js +52 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.js +11 -4
- package/dist/invite.d.ts +41 -2
- package/dist/invite.js +115 -2
- package/dist/outbound.d.ts +18 -3
- package/dist/outbound.js +7 -2
- package/dist/queue.d.ts +4 -0
- package/dist/queue.js +16 -10
- package/dist/receipts.d.ts +60 -0
- package/dist/receipts.js +118 -0
- package/dist/revoke.d.ts +71 -0
- package/dist/revoke.js +108 -0
- package/dist/section-status.d.ts +94 -0
- package/dist/section-status.js +16 -0
- package/dist/storage.d.ts +29 -0
- package/dist/storage.js +65 -0
- package/dist/sync-client.d.ts +148 -3
- package/dist/sync-client.js +736 -11
- package/dist/typing.d.ts +60 -0
- package/dist/typing.js +110 -0
- package/dist/write-access.d.ts +115 -0
- package/dist/write-access.js +87 -0
- package/package.json +6 -6
package/dist/typing.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Receipt } from "./receipts.js";
|
|
2
|
+
/** What submit did with a pass. */
|
|
3
|
+
export type Submitted =
|
|
4
|
+
/** Committed now: its receipt. */
|
|
5
|
+
{
|
|
6
|
+
readonly kind: "committed";
|
|
7
|
+
readonly receipt: Receipt;
|
|
8
|
+
readonly replaced: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** Waiting for more typing; `replaced` is the waiting pass it replaces, which is dropped. */
|
|
11
|
+
| {
|
|
12
|
+
readonly kind: "deferred";
|
|
13
|
+
readonly operationId: string;
|
|
14
|
+
readonly replaced: string | null;
|
|
15
|
+
};
|
|
16
|
+
/** A waiting pass committed by tick() or flush(), or its failure. */
|
|
17
|
+
export type Flushed = {
|
|
18
|
+
readonly kind: "committed";
|
|
19
|
+
readonly key: string;
|
|
20
|
+
readonly operationId: string;
|
|
21
|
+
readonly receipt: Receipt;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "failed";
|
|
24
|
+
readonly key: string;
|
|
25
|
+
readonly operationId: string;
|
|
26
|
+
readonly intents: readonly unknown[];
|
|
27
|
+
readonly error: unknown;
|
|
28
|
+
};
|
|
29
|
+
export interface TypingCoalescerOptions {
|
|
30
|
+
/** The durable commit (SyncClient.commit for the projection's Resource). */
|
|
31
|
+
commit(intents: readonly unknown[], options: {
|
|
32
|
+
readonly operationId: string;
|
|
33
|
+
}): Promise<Receipt>;
|
|
34
|
+
/** A waiting pass was committed or failed outside submit (tick, flush). */
|
|
35
|
+
onFlushed?(flushed: Flushed): void;
|
|
36
|
+
/** Idle pause after which a waiting pass is committed (ms, default 1,500). */
|
|
37
|
+
readonly idleMs?: number;
|
|
38
|
+
/** Characters inserted or deleted after which a pass is committed (default 256). */
|
|
39
|
+
readonly maxChars?: number;
|
|
40
|
+
/** The local clock (ms), for the idle pause. */
|
|
41
|
+
now(): number;
|
|
42
|
+
}
|
|
43
|
+
export declare class TypingCoalescer {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(options: TypingCoalescerOptions);
|
|
46
|
+
/**
|
|
47
|
+
* Commits `intents` now or lets them wait for more typing (see above).
|
|
48
|
+
* `key` names the projection whose base the pass was planned on.
|
|
49
|
+
*/
|
|
50
|
+
submit(key: string, intents: readonly unknown[], options: {
|
|
51
|
+
readonly operationId: string;
|
|
52
|
+
}): Promise<Submitted>;
|
|
53
|
+
/** Commits every pass that waited `idleMs` or longer at `now`, reporting each through onFlushed. */
|
|
54
|
+
tick(now: number): Promise<void>;
|
|
55
|
+
/** Commits the waiting pass of `key` (every key without one), reporting each through onFlushed. */
|
|
56
|
+
flush(key?: string): Promise<void>;
|
|
57
|
+
/** The operation ID of the pass waiting for `key`, if any. */
|
|
58
|
+
waiting(key: string): string | undefined;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=typing.d.ts.map
|
package/dist/typing.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const isTextEdit = (i) => typeof i === "object" &&
|
|
2
|
+
i !== null &&
|
|
3
|
+
i.intent === "text.edit" &&
|
|
4
|
+
typeof i.id === "string" &&
|
|
5
|
+
typeof i.base === "string" &&
|
|
6
|
+
Array.isArray(i.edits);
|
|
7
|
+
export class TypingCoalescer {
|
|
8
|
+
#o;
|
|
9
|
+
#idleMs;
|
|
10
|
+
#maxChars;
|
|
11
|
+
/** The waiting pass per key (a projection). */
|
|
12
|
+
#waiting = new Map();
|
|
13
|
+
/** Serializes commits per key. */
|
|
14
|
+
#chain = new Map();
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.#o = options;
|
|
17
|
+
this.#idleMs = options.idleMs ?? 1_500;
|
|
18
|
+
this.#maxChars = options.maxChars ?? 256;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Commits `intents` now or lets them wait for more typing (see above).
|
|
22
|
+
* `key` names the projection whose base the pass was planned on.
|
|
23
|
+
*/
|
|
24
|
+
submit(key, intents, options) {
|
|
25
|
+
return this.#serial(key, async () => {
|
|
26
|
+
const waiting = this.#waiting.get(key);
|
|
27
|
+
const textOnly = intents.length > 0 && intents.every(isTextEdit);
|
|
28
|
+
const edits = intents.filter(isTextEdit);
|
|
29
|
+
const bases = new Map(edits.map((e) => [e.id, e.base]));
|
|
30
|
+
// A later pass on the same base contains the waiting one and replaces
|
|
31
|
+
// it. A node edited on another base means the base moved without a
|
|
32
|
+
// flush: the waiting pass is not contained, so it is committed first.
|
|
33
|
+
let replaced = null;
|
|
34
|
+
if (waiting !== undefined) {
|
|
35
|
+
const sameBase = [...bases].every(([id, base]) => !waiting.bases.has(id) || waiting.bases.get(id) === base);
|
|
36
|
+
this.#drop(key);
|
|
37
|
+
if (sameBase)
|
|
38
|
+
replaced = waiting.operationId;
|
|
39
|
+
else
|
|
40
|
+
await this.#commitWaiting(key, waiting, false);
|
|
41
|
+
}
|
|
42
|
+
const chars = edits.reduce((n, e) => n + e.edits.reduce((m, x) => m + x.insert.length + x.deleteCount, 0), 0);
|
|
43
|
+
// The burst moved to another paragraph: the pass ends it.
|
|
44
|
+
const leftNode = waiting !== undefined &&
|
|
45
|
+
replaced !== null &&
|
|
46
|
+
[...bases.keys()].some((n) => !waiting.bases.has(n));
|
|
47
|
+
if (!textOnly || chars >= this.#maxChars || leftNode) {
|
|
48
|
+
const receipt = await this.#o.commit(intents, options);
|
|
49
|
+
return { kind: "committed", receipt, replaced };
|
|
50
|
+
}
|
|
51
|
+
const w = { operationId: options.operationId, intents, bases, at: this.#o.now() };
|
|
52
|
+
this.#waiting.set(key, w);
|
|
53
|
+
return { kind: "deferred", operationId: options.operationId, replaced };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** Commits every pass that waited `idleMs` or longer at `now`, reporting each through onFlushed. */
|
|
57
|
+
async tick(now) {
|
|
58
|
+
for (const [key, w] of [...this.#waiting])
|
|
59
|
+
if (now - w.at >= this.#idleMs)
|
|
60
|
+
await this.#serial(key, async () => {
|
|
61
|
+
if (this.#waiting.get(key) !== w)
|
|
62
|
+
return;
|
|
63
|
+
this.#waiting.delete(key);
|
|
64
|
+
await this.#commitWaiting(key, w, true);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Commits the waiting pass of `key` (every key without one), reporting each through onFlushed. */
|
|
68
|
+
async flush(key) {
|
|
69
|
+
const keys = key === undefined ? [...this.#waiting.keys()] : [key];
|
|
70
|
+
for (const k of keys)
|
|
71
|
+
await this.#serial(k, async () => {
|
|
72
|
+
const w = this.#waiting.get(k);
|
|
73
|
+
if (w === undefined)
|
|
74
|
+
return;
|
|
75
|
+
this.#drop(k);
|
|
76
|
+
await this.#commitWaiting(k, w, true);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** The operation ID of the pass waiting for `key`, if any. */
|
|
80
|
+
waiting(key) {
|
|
81
|
+
return this.#waiting.get(key)?.operationId;
|
|
82
|
+
}
|
|
83
|
+
#drop(key) {
|
|
84
|
+
this.#waiting.delete(key);
|
|
85
|
+
}
|
|
86
|
+
/** Commits a waiting pass; `report` sends the outcome to onFlushed, else a failure throws. */
|
|
87
|
+
async #commitWaiting(key, w, report) {
|
|
88
|
+
try {
|
|
89
|
+
const receipt = await this.#o.commit(w.intents, { operationId: w.operationId });
|
|
90
|
+
this.#o.onFlushed?.({ kind: "committed", key, operationId: w.operationId, receipt });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.#o.onFlushed?.({
|
|
94
|
+
kind: "failed",
|
|
95
|
+
key,
|
|
96
|
+
operationId: w.operationId,
|
|
97
|
+
intents: w.intents,
|
|
98
|
+
error,
|
|
99
|
+
});
|
|
100
|
+
if (!report)
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
#serial(key, fn) {
|
|
105
|
+
const run = (this.#chain.get(key) ?? Promise.resolve()).then(fn, fn);
|
|
106
|
+
this.#chain.set(key, run.catch(() => undefined));
|
|
107
|
+
return run;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=typing.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { type ControlRecordId, type PrincipalId } from "@openlfcp/core";
|
|
2
|
+
import { type ChainResult, type ControlBody } from "@openlfcp/wire";
|
|
3
|
+
/**
|
|
4
|
+
* Write access (SDK-SECTIONS-INTEGRATION-01 §6): whether this client may
|
|
5
|
+
* commit to a Resource, decided from the validated Control state only.
|
|
6
|
+
*/
|
|
7
|
+
/** §6: why writing is not allowed. */
|
|
8
|
+
export type WriteDeniedReason = "not-member" | "read-only" | "key-unavailable" | "revoked" | "unknown"
|
|
9
|
+
/**
|
|
10
|
+
* LFCP-02-115: the server refuses this client the Resource
|
|
11
|
+
* (AUTHORIZATION_FAILED on RESOURCE_OPEN) although the local chain grants
|
|
12
|
+
* it. The server does not say why: a revocation this client has not seen,
|
|
13
|
+
* or a server that lost state and could not be recovered (106).
|
|
14
|
+
*/
|
|
15
|
+
| "server-refused";
|
|
16
|
+
/** §6: the answer of canWrite. `controlHead` and `verifiedAt` are its freshness. */
|
|
17
|
+
export interface WriteAccess {
|
|
18
|
+
readonly allowed: boolean;
|
|
19
|
+
/** Why not, when not allowed; null when allowed. */
|
|
20
|
+
readonly reason: WriteDeniedReason | null;
|
|
21
|
+
/** The Control Head the decision was validated at; null without a validated chain. */
|
|
22
|
+
readonly controlHead: ControlRecordId | null;
|
|
23
|
+
/** The local time (ms since the epoch) of that validation; null without one. */
|
|
24
|
+
readonly verifiedAt: number | null;
|
|
25
|
+
}
|
|
26
|
+
/** §3.6: a batch submitted while writing is not allowed. A local SDK error; nothing is written. */
|
|
27
|
+
export declare class NotWritableError extends Error {
|
|
28
|
+
readonly access: WriteAccess;
|
|
29
|
+
readonly code = "NOT_WRITABLE";
|
|
30
|
+
constructor(access: WriteAccess);
|
|
31
|
+
}
|
|
32
|
+
/** The answer without a validated chain: unknown, never a default (§2). */
|
|
33
|
+
export declare const UNKNOWN_ACCESS: WriteAccess;
|
|
34
|
+
/**
|
|
35
|
+
* Decides write access for `principal` from a validated chain: `data/write`
|
|
36
|
+
* (LFCP-WIRE-01 §17) and the current epoch's DEK are both needed. Without
|
|
37
|
+
* `data/write`, a principal holding `data/read` is read-only, one whose
|
|
38
|
+
* every grant is inactive (revoked, or delegated from a revoked one, §17.2)
|
|
39
|
+
* is revoked, and anyone else is not a member.
|
|
40
|
+
*/
|
|
41
|
+
export declare function writeAccess(chain: ChainResult | undefined | null, principal: PrincipalId, hasCurrentDek: boolean, verifiedAt: number): WriteAccess;
|
|
42
|
+
/** One grant path to this principal (§17.2): an active grant naming it. */
|
|
43
|
+
export interface GrantPath {
|
|
44
|
+
readonly grantId: ControlRecordId;
|
|
45
|
+
readonly source: "grant" | "claim";
|
|
46
|
+
/** The ability names it lists. */
|
|
47
|
+
readonly abilities: readonly string[];
|
|
48
|
+
/** It is delegated from another grant (§17.2): active while that one is. */
|
|
49
|
+
readonly delegated: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** An invitation this principal issued (§18.1): not access of anyone until claimed. */
|
|
52
|
+
export interface IssuedInvitation {
|
|
53
|
+
readonly grantId: ControlRecordId;
|
|
54
|
+
readonly claimLimit: bigint;
|
|
55
|
+
readonly claimsUsed: bigint;
|
|
56
|
+
}
|
|
57
|
+
/** A Control Record of this principal sent and not committed yet (SI14): pending, never done. */
|
|
58
|
+
export interface PendingControl {
|
|
59
|
+
readonly recordId: ControlRecordId;
|
|
60
|
+
readonly type: ControlBody["type"];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* LFCP-02-027: write access with the evidence around it. `abilities` and
|
|
64
|
+
* `paths` are active access at `controlHead`; invitations issued, our own
|
|
65
|
+
* pending Control Records and an unsettled invitation claim are kept
|
|
66
|
+
* apart and never count as access.
|
|
67
|
+
*/
|
|
68
|
+
export interface AccessState extends WriteAccess {
|
|
69
|
+
/** The Control sequence of `controlHead`; null without a validated chain. */
|
|
70
|
+
readonly controlSeq: bigint | null;
|
|
71
|
+
/** The highest Control sequence a server reported in this session; null when none did. */
|
|
72
|
+
readonly serverControlSeq: bigint | null;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the validated chain reaches what the server reported: false
|
|
75
|
+
* while it is behind (a stale Control view: the access may already have
|
|
76
|
+
* changed), null when no server reported a head in this session.
|
|
77
|
+
*/
|
|
78
|
+
readonly current: boolean | null;
|
|
79
|
+
readonly owner: boolean;
|
|
80
|
+
/** Effective ability names (§17.1), over every active grant path. */
|
|
81
|
+
readonly abilities: readonly string[];
|
|
82
|
+
readonly paths: readonly GrantPath[];
|
|
83
|
+
readonly invitations: readonly IssuedInvitation[];
|
|
84
|
+
readonly pendingControl: readonly PendingControl[];
|
|
85
|
+
/** An invitation claim of this principal is journaled and not settled (LFCP-02-110). */
|
|
86
|
+
readonly pendingClaim: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* LFCP-02-115: the server refuses this client the Resource in this
|
|
89
|
+
* session; then `allowed` is false with reason "server-refused" and
|
|
90
|
+
* `current` is false, whatever the local chain says.
|
|
91
|
+
*/
|
|
92
|
+
readonly serverRefusal: ServerRefusal | null;
|
|
93
|
+
}
|
|
94
|
+
/** LFCP-02-115: the server's refusal of the Resource in this session, as far as it is known. */
|
|
95
|
+
export interface ServerRefusal {
|
|
96
|
+
/** The §62 code, AUTHORIZATION_FAILED. */
|
|
97
|
+
readonly code: string;
|
|
98
|
+
/**
|
|
99
|
+
* How the access recovery (LFCP-02-106) ended, when it ran: "unknown-head"
|
|
100
|
+
* (the server holds Control Records this client has not seen), "refused",
|
|
101
|
+
* "still-refused", "not-granted", "server-current"; null when it did not run.
|
|
102
|
+
*/
|
|
103
|
+
readonly recovery: string | null;
|
|
104
|
+
}
|
|
105
|
+
/** The evidence of `accessState` the chain does not hold. */
|
|
106
|
+
export interface AccessContext {
|
|
107
|
+
/** The server refuses the Resource in this session (LFCP-02-115). */
|
|
108
|
+
readonly serverRefusal?: ServerRefusal | null;
|
|
109
|
+
readonly serverControlSeq: bigint | null;
|
|
110
|
+
readonly pendingControl: readonly PendingControl[];
|
|
111
|
+
readonly pendingClaim: boolean;
|
|
112
|
+
}
|
|
113
|
+
/** AccessState from a validated chain (see writeAccess) and the context around it. */
|
|
114
|
+
export declare function accessState(chain: ChainResult | undefined | null, principal: PrincipalId, hasCurrentDek: boolean, verifiedAt: number, context: AccessContext): AccessState;
|
|
115
|
+
//# sourceMappingURL=write-access.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { bytesEqual } from "@openlfcp/core";
|
|
2
|
+
import { ABILITY, ABILITY_NAMES, abilitiesOf, hasAbility, isGrantActive, } from "@openlfcp/wire";
|
|
3
|
+
/** §3.6: a batch submitted while writing is not allowed. A local SDK error; nothing is written. */
|
|
4
|
+
export class NotWritableError extends Error {
|
|
5
|
+
access;
|
|
6
|
+
code = "NOT_WRITABLE";
|
|
7
|
+
constructor(access) {
|
|
8
|
+
super(`writing is not allowed: ${access.reason ?? "unknown"} (SDK-SECTIONS-INTEGRATION-01 §6)`);
|
|
9
|
+
this.access = access;
|
|
10
|
+
this.name = "NotWritableError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** The answer without a validated chain: unknown, never a default (§2). */
|
|
14
|
+
export const UNKNOWN_ACCESS = Object.freeze({
|
|
15
|
+
allowed: false,
|
|
16
|
+
reason: "unknown",
|
|
17
|
+
controlHead: null,
|
|
18
|
+
verifiedAt: null,
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Decides write access for `principal` from a validated chain: `data/write`
|
|
22
|
+
* (LFCP-WIRE-01 §17) and the current epoch's DEK are both needed. Without
|
|
23
|
+
* `data/write`, a principal holding `data/read` is read-only, one whose
|
|
24
|
+
* every grant is inactive (revoked, or delegated from a revoked one, §17.2)
|
|
25
|
+
* is revoked, and anyone else is not a member.
|
|
26
|
+
*/
|
|
27
|
+
export function writeAccess(chain, principal, hasCurrentDek, verifiedAt) {
|
|
28
|
+
if (chain?.kind !== "linear")
|
|
29
|
+
return UNKNOWN_ACCESS;
|
|
30
|
+
const { state } = chain;
|
|
31
|
+
const at = { controlHead: state.head, verifiedAt };
|
|
32
|
+
const denied = (reason) => Object.freeze({ allowed: false, reason, ...at });
|
|
33
|
+
if (!hasAbility(state, principal, ABILITY.DATA_WRITE)) {
|
|
34
|
+
if (hasAbility(state, principal, ABILITY.DATA_READ))
|
|
35
|
+
return denied("read-only");
|
|
36
|
+
const grants = [...state.grants.values()].filter((g) => bytesEqual(g.subject, principal));
|
|
37
|
+
return denied(grants.some((g) => !isGrantActive(state, g.id)) ? "revoked" : "not-member");
|
|
38
|
+
}
|
|
39
|
+
if (!hasCurrentDek)
|
|
40
|
+
return denied("key-unavailable");
|
|
41
|
+
return Object.freeze({ allowed: true, reason: null, ...at });
|
|
42
|
+
}
|
|
43
|
+
/** AccessState from a validated chain (see writeAccess) and the context around it. */
|
|
44
|
+
export function accessState(chain, principal, hasCurrentDek, verifiedAt, context) {
|
|
45
|
+
const write = writeAccess(chain, principal, hasCurrentDek, verifiedAt);
|
|
46
|
+
const state = chain?.kind === "linear" ? chain.state : undefined;
|
|
47
|
+
const controlSeq = state?.seq ?? null;
|
|
48
|
+
const server = context.serverControlSeq;
|
|
49
|
+
const name = (a) => ABILITY_NAMES.get(a) ?? `${a}`;
|
|
50
|
+
const grants = state === undefined ? [] : [...state.grants.values()];
|
|
51
|
+
const refusal = context.serverRefusal ?? null;
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
...write,
|
|
54
|
+
...(refusal === null ? {} : { allowed: false, reason: "server-refused" }),
|
|
55
|
+
controlSeq,
|
|
56
|
+
serverControlSeq: server,
|
|
57
|
+
current: refusal !== null
|
|
58
|
+
? false
|
|
59
|
+
: server === null || controlSeq === null
|
|
60
|
+
? null
|
|
61
|
+
: controlSeq >= server,
|
|
62
|
+
owner: state !== undefined && bytesEqual(state.owner.principalId, principal),
|
|
63
|
+
abilities: Object.freeze(state === undefined ? [] : abilitiesOf(state, principal).map(name)),
|
|
64
|
+
paths: Object.freeze(grants
|
|
65
|
+
.filter((g) => state !== undefined && bytesEqual(g.subject, principal) && isGrantActive(state, g.id))
|
|
66
|
+
.map((g) => Object.freeze({
|
|
67
|
+
grantId: g.id,
|
|
68
|
+
source: g.source,
|
|
69
|
+
abilities: Object.freeze(g.abilities.map(name)),
|
|
70
|
+
delegated: g.parentGrantId !== null,
|
|
71
|
+
}))),
|
|
72
|
+
invitations: Object.freeze(grants
|
|
73
|
+
.filter((g) => state !== undefined &&
|
|
74
|
+
g.claimLimit !== null &&
|
|
75
|
+
bytesEqual(g.issuer, principal) &&
|
|
76
|
+
isGrantActive(state, g.id))
|
|
77
|
+
.map((g) => Object.freeze({
|
|
78
|
+
grantId: g.id,
|
|
79
|
+
claimLimit: g.claimLimit,
|
|
80
|
+
claimsUsed: g.claimsUsed,
|
|
81
|
+
}))),
|
|
82
|
+
pendingControl: Object.freeze([...context.pendingControl]),
|
|
83
|
+
pendingClaim: context.pendingClaim,
|
|
84
|
+
serverRefusal: refusal === null ? null : Object.freeze({ ...refusal }),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=write-access.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openlfcp/client",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
4
|
"description": "LFCP client: session, Control Plane and Data Plane synchronization.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openlfcp",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
],
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public",
|
|
42
|
-
"tag": "
|
|
42
|
+
"tag": "beta"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@openlfcp/core": "^0.1
|
|
46
|
-
"@openlfcp/crypto": "^0.1
|
|
47
|
-
"@openlfcp/
|
|
48
|
-
"@openlfcp/
|
|
45
|
+
"@openlfcp/core": "^0.2.0-beta.1",
|
|
46
|
+
"@openlfcp/crypto": "^0.2.0-beta.1",
|
|
47
|
+
"@openlfcp/storage": "^0.2.0-beta.1",
|
|
48
|
+
"@openlfcp/wire": "^0.2.0-beta.1"
|
|
49
49
|
}
|
|
50
50
|
}
|