@oatscenter/trellis 0.100.0-rc.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 +59 -0
- package/auth/authorization/client_context.d.ts +61 -0
- package/auth/authorization/client_context.js +266 -0
- package/auth/authorization/nats_registry.d.ts +41 -0
- package/auth/authorization/nats_registry.js +283 -0
- package/auth/authorization/provider_cache.d.ts +90 -0
- package/auth/authorization/provider_cache.js +783 -0
- package/auth/authorization/refresh.d.ts +46 -0
- package/auth/authorization/refresh.js +246 -0
- package/auth/authorization/types.d.ts +207 -0
- package/auth/authorization/types.js +60 -0
- package/auth/authorization_context.d.ts +11 -0
- package/auth/authorization_context.js +10 -0
- package/auth/browser/flow_types.d.ts +84 -0
- package/auth/browser/flow_types.js +70 -0
- package/auth/browser/portal.d.ts +21 -0
- package/auth/browser/portal.js +307 -0
- package/auth/browser/storage.d.ts +26 -0
- package/auth/browser/storage.js +224 -0
- package/auth/browser.d.ts +11 -0
- package/auth/browser.js +10 -0
- package/auth/browser_recovery.d.ts +13 -0
- package/auth/browser_recovery.js +38 -0
- package/auth/device_activation.d.ts +134 -0
- package/auth/device_activation.js +376 -0
- package/auth/http_error.d.ts +12 -0
- package/auth/http_error.js +32 -0
- package/auth/keys.d.ts +5 -0
- package/auth/keys.js +63 -0
- package/auth/mod.d.ts +16 -0
- package/auth/mod.js +16 -0
- package/auth/proof.d.ts +31 -0
- package/auth/proof.js +95 -0
- package/auth/protocol_wasm/trellis_protocol_wasm.d.ts +138 -0
- package/auth/protocol_wasm/trellis_protocol_wasm.js +605 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bg.wasm +0 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.d.ts +1 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.js +2 -0
- package/auth/protocol_wasm.d.ts +179 -0
- package/auth/protocol_wasm.js +133 -0
- package/auth/session_auth.d.ts +30 -0
- package/auth/session_auth.js +77 -0
- package/auth/session_proof.d.ts +53 -0
- package/auth/session_proof.js +43 -0
- package/auth/time.d.ts +6 -0
- package/auth/time.js +7 -0
- package/auth/trellis_id.d.ts +1 -0
- package/auth/trellis_id.js +5 -0
- package/auth/utils.d.ts +10 -0
- package/auth/utils.js +69 -0
- package/auth.d.ts +1 -0
- package/auth.js +1 -0
- package/caller.d.ts +111 -0
- package/caller.js +85 -0
- package/client.d.ts +14 -0
- package/client.js +1 -0
- package/client_connect.d.ts +143 -0
- package/client_connect.js +1097 -0
- package/codec.d.ts +13 -0
- package/codec.js +192 -0
- package/connection.d.ts +107 -0
- package/connection.js +396 -0
- package/device/activation.d.ts +42 -0
- package/device/activation.js +319 -0
- package/device.d.ts +80 -0
- package/device.js +687 -0
- package/env.d.ts +2 -0
- package/env.js +10 -0
- package/errors/AuthError.d.ts +30 -0
- package/errors/AuthError.js +34 -0
- package/errors/KVError.d.ts +30 -0
- package/errors/KVError.js +36 -0
- package/errors/OperationLifecycleError.d.ts +110 -0
- package/errors/OperationLifecycleError.js +142 -0
- package/errors/RemoteError.d.ts +61 -0
- package/errors/RemoteError.js +72 -0
- package/errors/SchemaValidationError.d.ts +48 -0
- package/errors/SchemaValidationError.js +49 -0
- package/errors/StoreError.d.ts +21 -0
- package/errors/StoreError.js +31 -0
- package/errors/TransferError.d.ts +21 -0
- package/errors/TransferError.js +31 -0
- package/errors/TransportError.d.ts +29 -0
- package/errors/TransportError.js +33 -0
- package/errors/TrellisError.d.ts +15 -0
- package/errors/TrellisError.js +15 -0
- package/errors/ValidationError.d.ts +50 -0
- package/errors/ValidationError.js +59 -0
- package/errors/index.d.ts +254 -0
- package/errors/index.js +238 -0
- package/generated.d.ts +4 -0
- package/generated.js +3 -0
- package/generated_support.d.ts +120 -0
- package/generated_support.js +359 -0
- package/globals.d.ts +9 -0
- package/globals.js +16 -0
- package/health_transport.d.ts +18 -0
- package/health_transport.js +32 -0
- package/helpers.d.ts +11 -0
- package/helpers.js +53 -0
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/internal_sdk/generated/apis/auth/mod.d.ts +805 -0
- package/internal_sdk/generated/apis/auth/mod.js +958 -0
- package/internal_sdk/generated/apis/core/mod.d.ts +79 -0
- package/internal_sdk/generated/apis/core/mod.js +93 -0
- package/internal_sdk/generated/apis/events/mod.d.ts +224 -0
- package/internal_sdk/generated/apis/events/mod.js +313 -0
- package/internal_sdk/generated/apis/health/mod.d.ts +106 -0
- package/internal_sdk/generated/apis/health/mod.js +132 -0
- package/internal_sdk/generated/apis/index.d.ts +7 -0
- package/internal_sdk/generated/apis/index.js +8 -0
- package/internal_sdk/generated/apis/jobs/mod.d.ts +176 -0
- package/internal_sdk/generated/apis/jobs/mod.js +209 -0
- package/internal_sdk/generated/apis/state/mod.d.ts +104 -0
- package/internal_sdk/generated/apis/state/mod.js +139 -0
- package/internal_sdk/generated/index.d.ts +4 -0
- package/internal_sdk/generated/index.js +5 -0
- package/internal_sdk/generated/package.json +18 -0
- package/internal_sdk/generated/participants/cli/mod.d.ts +402 -0
- package/internal_sdk/generated/participants/cli/mod.js +460 -0
- package/internal_sdk/generated/participants/cli/types.d.ts +2 -0
- package/internal_sdk/generated/participants/cli/types.js +3 -0
- package/internal_sdk/generated/participants/console/mod.d.ts +489 -0
- package/internal_sdk/generated/participants/console/mod.js +579 -0
- package/internal_sdk/generated/participants/console/types.d.ts +2 -0
- package/internal_sdk/generated/participants/console/types.js +3 -0
- package/internal_sdk/generated/participants/eventsRuntime/mod.d.ts +64 -0
- package/internal_sdk/generated/participants/eventsRuntime/mod.js +42 -0
- package/internal_sdk/generated/participants/eventsRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/eventsRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/healthRuntime/mod.d.ts +58 -0
- package/internal_sdk/generated/participants/healthRuntime/mod.js +36 -0
- package/internal_sdk/generated/participants/healthRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/healthRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/index.d.ts +8 -0
- package/internal_sdk/generated/participants/index.js +9 -0
- package/internal_sdk/generated/participants/jobsRuntime/mod.d.ts +64 -0
- package/internal_sdk/generated/participants/jobsRuntime/mod.js +42 -0
- package/internal_sdk/generated/participants/jobsRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/jobsRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/platform/mod.d.ts +164 -0
- package/internal_sdk/generated/participants/platform/mod.js +149 -0
- package/internal_sdk/generated/participants/platform/types.d.ts +7 -0
- package/internal_sdk/generated/participants/platform/types.js +5 -0
- package/internal_sdk/generated/participants/portal/mod.d.ts +131 -0
- package/internal_sdk/generated/participants/portal/mod.js +109 -0
- package/internal_sdk/generated/participants/portal/types.d.ts +2 -0
- package/internal_sdk/generated/participants/portal/types.js +3 -0
- package/internal_sdk/generated/types/_internal/p0.d.ts +13511 -0
- package/internal_sdk/generated/types/_internal/p0.js +6105 -0
- package/internal_sdk/generated/types/index.d.ts +2951 -0
- package/internal_sdk/generated/types/index.js +1477 -0
- package/jobs.d.ts +309 -0
- package/jobs.js +389 -0
- package/kv.d.ts +85 -0
- package/kv.js +330 -0
- package/operations.d.ts +189 -0
- package/operations.js +847 -0
- package/package.json +73 -0
- package/pagination.d.ts +25 -0
- package/pagination.js +117 -0
- package/participant.d.ts +6 -0
- package/participant.js +6 -0
- package/participant_runtime/api.d.ts +131 -0
- package/participant_runtime/api.js +42 -0
- package/participant_runtime/json.d.ts +16 -0
- package/participant_runtime/json.js +193 -0
- package/participant_runtime/metadata.d.ts +34 -0
- package/participant_runtime/metadata.js +4 -0
- package/participant_runtime/participant.d.ts +200 -0
- package/participant_runtime/participant.js +330 -0
- package/participant_runtime/schemas.d.ts +347 -0
- package/participant_runtime/schemas.js +211 -0
- package/participant_runtime/surface_names.d.ts +16 -0
- package/participant_runtime/surface_names.js +34 -0
- package/portable.d.ts +30 -0
- package/portable.js +14 -0
- package/provider.d.ts +69 -0
- package/provider.js +68 -0
- package/runtime_transport.d.ts +25 -0
- package/runtime_transport.js +48 -0
- package/service/mod.d.ts +14 -0
- package/service/mod.js +13 -0
- package/service/outbox_inbox.d.ts +259 -0
- package/service/outbox_inbox.js +908 -0
- package/service/runtime/bootstrap.d.ts +56 -0
- package/service/runtime/bootstrap.js +226 -0
- package/service/runtime/core.d.ts +46 -0
- package/service/runtime/core.js +1747 -0
- package/service/runtime/health.d.ts +97 -0
- package/service/runtime/health.js +153 -0
- package/service/runtime/health_schemas.d.ts +23 -0
- package/service/runtime/health_schemas.js +20 -0
- package/service/runtime/internal_jobs/active-job.d.ts +40 -0
- package/service/runtime/internal_jobs/active-job.js +91 -0
- package/service/runtime/internal_jobs/bindings.d.ts +40 -0
- package/service/runtime/internal_jobs/bindings.js +1 -0
- package/service/runtime/internal_jobs/cancellation-registry.d.ts +13 -0
- package/service/runtime/internal_jobs/cancellation-registry.js +55 -0
- package/service/runtime/internal_jobs/heartbeat.d.ts +33 -0
- package/service/runtime/internal_jobs/heartbeat.js +65 -0
- package/service/runtime/internal_jobs/job-manager.d.ts +126 -0
- package/service/runtime/internal_jobs/job-manager.js +821 -0
- package/service/runtime/internal_jobs/key-coordinator.d.ts +280 -0
- package/service/runtime/internal_jobs/key-coordinator.js +747 -0
- package/service/runtime/internal_jobs/projection.d.ts +3 -0
- package/service/runtime/internal_jobs/projection.js +42 -0
- package/service/runtime/internal_jobs/runtime-worker.d.ts +126 -0
- package/service/runtime/internal_jobs/runtime-worker.js +454 -0
- package/service/runtime/internal_jobs/types.d.ts +246 -0
- package/service/runtime/internal_jobs/types.js +163 -0
- package/service/runtime/logger.d.ts +2 -0
- package/service/runtime/logger.js +7 -0
- package/service/runtime/runtime.d.ts +16 -0
- package/service/runtime/runtime.js +1 -0
- package/service/runtime/service.d.ts +372 -0
- package/service/runtime/service.js +1896 -0
- package/service/runtime/transfer/download.d.ts +27 -0
- package/service/runtime/transfer/download.js +1 -0
- package/service/runtime/transfer/protocol.d.ts +15 -0
- package/service/runtime/transfer/protocol.js +46 -0
- package/service/runtime/transfer/queue.d.ts +18 -0
- package/service/runtime/transfer/queue.js +136 -0
- package/service/runtime/transfer/upload.d.ts +40 -0
- package/service/runtime/transfer/upload.js +27 -0
- package/service/runtime/transfer.d.ts +62 -0
- package/service/runtime/transfer.js +763 -0
- package/session.d.ts +862 -0
- package/session.js +3407 -0
- package/store.d.ts +71 -0
- package/store.js +412 -0
- package/store_entry.d.ts +20 -0
- package/store_entry.js +75 -0
- package/tasks.d.ts +10 -0
- package/tasks.js +28 -0
- package/telemetry/carrier.d.ts +8 -0
- package/telemetry/carrier.js +20 -0
- package/telemetry/core.d.ts +7 -0
- package/telemetry/core.js +14 -0
- package/telemetry/env.d.ts +2 -0
- package/telemetry/env.js +10 -0
- package/telemetry/init.d.ts +2 -0
- package/telemetry/init.js +7 -0
- package/telemetry/metrics.d.ts +81 -0
- package/telemetry/metrics.js +267 -0
- package/telemetry/mod.d.ts +13 -0
- package/telemetry/mod.js +8 -0
- package/telemetry/nats.d.ts +6 -0
- package/telemetry/nats.js +6 -0
- package/telemetry/result.d.ts +1 -0
- package/telemetry/result.js +18 -0
- package/telemetry/runtime.d.ts +1 -0
- package/telemetry/runtime.js +141 -0
- package/telemetry/trace.d.ts +4 -0
- package/telemetry/trace.js +26 -0
- package/telemetry/trellis.d.ts +1 -0
- package/telemetry/trellis.js +1 -0
- package/telemetry.d.ts +1 -0
- package/telemetry.js +1 -0
- package/transfer.d.ts +112 -0
- package/transfer.js +525 -0
- package/transfer_protocol.d.ts +1 -0
- package/transfer_protocol.js +13 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { env, platform } from "node:process";
|
|
4
|
+
import { Type } from "typebox";
|
|
5
|
+
import { Value } from "typebox/value";
|
|
6
|
+
import { ulid } from "ulid";
|
|
7
|
+
import { deriveDeviceConfirmationCode, deriveDeviceIdentity } from "../auth.js";
|
|
8
|
+
import { resumeDeviceActivationWithDeps, startDeviceActivationWithDeps, } from "../device.js";
|
|
9
|
+
import { TransportError } from "../errors/index.js";
|
|
10
|
+
import { base64urlDecode, base64urlEncode } from "../auth/utils.js";
|
|
11
|
+
const PendingActivationStateSchema = Type.Object({
|
|
12
|
+
status: Type.Literal("pending"),
|
|
13
|
+
participantId: Type.String({ minLength: 1 }),
|
|
14
|
+
publicIdentityKey: Type.String({ minLength: 1 }),
|
|
15
|
+
instanceId: Type.String({ minLength: 1 }),
|
|
16
|
+
deploymentId: Type.String({ minLength: 1 }),
|
|
17
|
+
flowId: Type.String({ minLength: 1 }),
|
|
18
|
+
nonce: Type.String({ minLength: 1 }),
|
|
19
|
+
activationUrl: Type.String({ minLength: 1 }),
|
|
20
|
+
});
|
|
21
|
+
const ActivatedActivationStateSchema = Type.Object({
|
|
22
|
+
status: Type.Literal("activated"),
|
|
23
|
+
participantId: Type.String({ minLength: 1 }),
|
|
24
|
+
publicIdentityKey: Type.String({ minLength: 1 }),
|
|
25
|
+
instanceId: Type.String({ minLength: 1 }),
|
|
26
|
+
deploymentId: Type.String({ minLength: 1 }),
|
|
27
|
+
flowId: Type.String({ minLength: 1 }),
|
|
28
|
+
nonce: Type.String({ minLength: 1 }),
|
|
29
|
+
activationUrl: Type.String({ minLength: 1 }),
|
|
30
|
+
});
|
|
31
|
+
const LocalActivationStateSchema = Type.Union([
|
|
32
|
+
PendingActivationStateSchema,
|
|
33
|
+
ActivatedActivationStateSchema,
|
|
34
|
+
]);
|
|
35
|
+
const PersistedActivationStateSchema = Type.Object({
|
|
36
|
+
version: Type.Literal(1),
|
|
37
|
+
localState: LocalActivationStateSchema,
|
|
38
|
+
});
|
|
39
|
+
function normalizeRootSecret(rootSecret) {
|
|
40
|
+
if (typeof rootSecret === "string") {
|
|
41
|
+
const decoded = base64urlDecode(rootSecret.trim());
|
|
42
|
+
if (decoded.length === 0) {
|
|
43
|
+
throw new Error("rootSecret must not be empty");
|
|
44
|
+
}
|
|
45
|
+
return decoded;
|
|
46
|
+
}
|
|
47
|
+
if (rootSecret.length === 0) {
|
|
48
|
+
throw new Error("rootSecret must not be empty");
|
|
49
|
+
}
|
|
50
|
+
return rootSecret;
|
|
51
|
+
}
|
|
52
|
+
function isNotFoundError(error) {
|
|
53
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
54
|
+
}
|
|
55
|
+
function isAlreadyExistsError(error) {
|
|
56
|
+
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
57
|
+
}
|
|
58
|
+
function tempStatePath(statePath) {
|
|
59
|
+
return `${statePath}.tmp-${ulid()}`;
|
|
60
|
+
}
|
|
61
|
+
function backupStatePath(statePath) {
|
|
62
|
+
return `${statePath}.bak`;
|
|
63
|
+
}
|
|
64
|
+
function defaultActivationStateDir() {
|
|
65
|
+
if (platform === "win32") {
|
|
66
|
+
const base = env.LOCALAPPDATA ?? env.APPDATA;
|
|
67
|
+
if (!base) {
|
|
68
|
+
throw new Error("Could not resolve a default Trellis device state directory: LOCALAPPDATA or APPDATA is not set.");
|
|
69
|
+
}
|
|
70
|
+
return join(base, "Trellis", "device-activation");
|
|
71
|
+
}
|
|
72
|
+
const home = env.HOME;
|
|
73
|
+
if (!home) {
|
|
74
|
+
throw new Error("Could not resolve a default Trellis device state directory: HOME is not set.");
|
|
75
|
+
}
|
|
76
|
+
if (platform === "darwin") {
|
|
77
|
+
return join(home, "Library", "Application Support", "Trellis", "device-activation");
|
|
78
|
+
}
|
|
79
|
+
return join(env.XDG_STATE_HOME ?? join(home, ".local", "state"), "trellis", "device-activation");
|
|
80
|
+
}
|
|
81
|
+
async function hashOrigin(origin) {
|
|
82
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(origin));
|
|
83
|
+
return base64urlEncode(new Uint8Array(digest));
|
|
84
|
+
}
|
|
85
|
+
async function deriveStoreIdentity(args) {
|
|
86
|
+
const identity = await deriveDeviceIdentity(normalizeRootSecret(args.rootSecret));
|
|
87
|
+
return {
|
|
88
|
+
publicIdentityKey: identity.publicIdentityKey,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function parsePersistedState(text) {
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(text);
|
|
95
|
+
}
|
|
96
|
+
catch (cause) {
|
|
97
|
+
throw new Error("Stored Trellis device activation state is not valid JSON.", {
|
|
98
|
+
cause,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (!Value.Check(PersistedActivationStateSchema, parsed)) {
|
|
102
|
+
throw new Error("Stored Trellis device activation state has an invalid shape.");
|
|
103
|
+
}
|
|
104
|
+
const persisted = Value.Parse(PersistedActivationStateSchema, parsed);
|
|
105
|
+
return persisted.localState;
|
|
106
|
+
}
|
|
107
|
+
function assertLocalStateMatchesIdentity(args) {
|
|
108
|
+
if (args.state.publicIdentityKey !== args.publicIdentityKey) {
|
|
109
|
+
throw new Error("Stored Trellis device activation state does not match the provided root secret.");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function assertLocalStateMatchesContract(args) {
|
|
113
|
+
if (args.state.participantId !== args.participantId) {
|
|
114
|
+
throw new Error("Stored Trellis device activation state belongs to another participant.");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function resolveDeviceActivationStatePath(args) {
|
|
118
|
+
if (args.statePath) {
|
|
119
|
+
return args.statePath;
|
|
120
|
+
}
|
|
121
|
+
const { publicIdentityKey } = await deriveStoreIdentity(args);
|
|
122
|
+
const origin = new URL(args.trellisUrl).origin;
|
|
123
|
+
const originHash = await hashOrigin(origin);
|
|
124
|
+
const fileName = `activation-state-v1-${originHash}-${encodeURIComponent(args.participantId)}-${publicIdentityKey}.json`;
|
|
125
|
+
return join(args.stateDir ?? defaultActivationStateDir(), fileName);
|
|
126
|
+
}
|
|
127
|
+
async function openDeviceActivationStateStore(args) {
|
|
128
|
+
const { publicIdentityKey } = await deriveStoreIdentity(args);
|
|
129
|
+
const statePath = await resolveDeviceActivationStatePath(args);
|
|
130
|
+
const stateBackupPath = backupStatePath(statePath);
|
|
131
|
+
return {
|
|
132
|
+
statePath,
|
|
133
|
+
async load() {
|
|
134
|
+
for (const path of [statePath, stateBackupPath]) {
|
|
135
|
+
try {
|
|
136
|
+
const text = new TextDecoder().decode(await readFile(path));
|
|
137
|
+
const state = parsePersistedState(text);
|
|
138
|
+
assertLocalStateMatchesIdentity({ state, publicIdentityKey });
|
|
139
|
+
assertLocalStateMatchesContract({
|
|
140
|
+
state,
|
|
141
|
+
participantId: args.participantId,
|
|
142
|
+
});
|
|
143
|
+
return state;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (isNotFoundError(error)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
},
|
|
154
|
+
async save(state) {
|
|
155
|
+
if (!Value.Check(LocalActivationStateSchema, state)) {
|
|
156
|
+
throw new Error("Trellis device activation state has an invalid shape.");
|
|
157
|
+
}
|
|
158
|
+
assertLocalStateMatchesIdentity({ state, publicIdentityKey });
|
|
159
|
+
assertLocalStateMatchesContract({
|
|
160
|
+
state,
|
|
161
|
+
participantId: args.participantId,
|
|
162
|
+
});
|
|
163
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
164
|
+
const nextText = JSON.stringify({ version: 1, localState: state }, null, 2) +
|
|
165
|
+
"\n";
|
|
166
|
+
const nextPath = tempStatePath(statePath);
|
|
167
|
+
try {
|
|
168
|
+
await writeFile(nextPath, nextText, "utf8");
|
|
169
|
+
try {
|
|
170
|
+
await rename(nextPath, statePath);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (!isAlreadyExistsError(error)) {
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
await unlink(stateBackupPath);
|
|
178
|
+
}
|
|
179
|
+
catch (backupError) {
|
|
180
|
+
if (!isNotFoundError(backupError)) {
|
|
181
|
+
throw backupError;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await rename(statePath, stateBackupPath);
|
|
185
|
+
try {
|
|
186
|
+
await rename(nextPath, statePath);
|
|
187
|
+
await unlink(stateBackupPath);
|
|
188
|
+
}
|
|
189
|
+
catch (renameError) {
|
|
190
|
+
try {
|
|
191
|
+
await rename(stateBackupPath, statePath);
|
|
192
|
+
}
|
|
193
|
+
catch (rollbackError) {
|
|
194
|
+
if (!isNotFoundError(rollbackError)) {
|
|
195
|
+
throw rollbackError;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
throw renameError;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
try {
|
|
204
|
+
await unlink(nextPath);
|
|
205
|
+
}
|
|
206
|
+
catch (cleanupError) {
|
|
207
|
+
if (!isNotFoundError(cleanupError)) {
|
|
208
|
+
throw cleanupError;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function activatedStatus() {
|
|
217
|
+
return { status: "activated" };
|
|
218
|
+
}
|
|
219
|
+
function createActivatedLocalState(localState) {
|
|
220
|
+
return {
|
|
221
|
+
...localState,
|
|
222
|
+
status: "activated",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async function createActivationRequiredStatus(args) {
|
|
226
|
+
const session = args.localState?.status === "pending"
|
|
227
|
+
? await resumeDeviceActivationWithDeps({
|
|
228
|
+
trellisUrl: args.checkArgs.trellisUrl,
|
|
229
|
+
participant: args.checkArgs.participant,
|
|
230
|
+
provisioningSecret: args.checkArgs.provisioningSecret,
|
|
231
|
+
rootSecret: args.checkArgs.rootSecret,
|
|
232
|
+
localState: args.localState,
|
|
233
|
+
}, { now: () => Date.now() })
|
|
234
|
+
: await startDeviceActivationWithDeps({
|
|
235
|
+
trellisUrl: args.checkArgs.trellisUrl,
|
|
236
|
+
participant: args.checkArgs.participant,
|
|
237
|
+
provisioningSecret: args.checkArgs.provisioningSecret,
|
|
238
|
+
rootSecret: args.checkArgs.rootSecret,
|
|
239
|
+
}, { now: () => Date.now() });
|
|
240
|
+
if (args.localState?.status !== "pending") {
|
|
241
|
+
await args.store.save(session.localState);
|
|
242
|
+
}
|
|
243
|
+
let completedState = null;
|
|
244
|
+
const identity = await deriveDeviceIdentity(normalizeRootSecret(args.checkArgs.rootSecret));
|
|
245
|
+
const confirmationCode = await deriveDeviceConfirmationCode({
|
|
246
|
+
activationKey: identity.activationKey,
|
|
247
|
+
publicIdentityKey: identity.publicIdentityKey,
|
|
248
|
+
nonce: session.localState.nonce,
|
|
249
|
+
});
|
|
250
|
+
let completionPromise = null;
|
|
251
|
+
const finish = async (nextState) => {
|
|
252
|
+
if (completedState) {
|
|
253
|
+
return activatedStatus();
|
|
254
|
+
}
|
|
255
|
+
if (completionPromise) {
|
|
256
|
+
return await completionPromise;
|
|
257
|
+
}
|
|
258
|
+
completionPromise = (async () => {
|
|
259
|
+
const nextCompletedState = await nextState();
|
|
260
|
+
await args.store.save(nextCompletedState);
|
|
261
|
+
completedState = nextCompletedState;
|
|
262
|
+
return activatedStatus();
|
|
263
|
+
})();
|
|
264
|
+
try {
|
|
265
|
+
return await completionPromise;
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
completionPromise = null;
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
return {
|
|
273
|
+
status: "activation_required",
|
|
274
|
+
activationUrl: session.activationUrl,
|
|
275
|
+
confirmationCode,
|
|
276
|
+
waitForOnlineApproval(opts) {
|
|
277
|
+
return finish(() => session.waitForOnlineApproval(opts));
|
|
278
|
+
},
|
|
279
|
+
acceptConfirmationCode(code) {
|
|
280
|
+
return finish(() => session.acceptConfirmationCode(code));
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Reports native device activation status and hides local activation persistence details.
|
|
286
|
+
*/
|
|
287
|
+
export async function checkDeviceActivation(args) {
|
|
288
|
+
const store = await openDeviceActivationStateStore({
|
|
289
|
+
trellisUrl: args.trellisUrl,
|
|
290
|
+
rootSecret: args.rootSecret,
|
|
291
|
+
participantId: args.participant.identity,
|
|
292
|
+
stateDir: args.stateDir,
|
|
293
|
+
statePath: args.statePath,
|
|
294
|
+
});
|
|
295
|
+
const localState = await store.load();
|
|
296
|
+
try {
|
|
297
|
+
return await createActivationRequiredStatus({
|
|
298
|
+
checkArgs: args,
|
|
299
|
+
store,
|
|
300
|
+
localState,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (error instanceof TransportError &&
|
|
305
|
+
error.code === "device_activation_unavailable" &&
|
|
306
|
+
error.getContext().status === "ready") {
|
|
307
|
+
if (localState?.status === "pending") {
|
|
308
|
+
await store.save(createActivatedLocalState(localState));
|
|
309
|
+
}
|
|
310
|
+
return activatedStatus();
|
|
311
|
+
}
|
|
312
|
+
if (error instanceof TransportError &&
|
|
313
|
+
error.code === "device_activation_unavailable" &&
|
|
314
|
+
error.getContext().status === "not_ready") {
|
|
315
|
+
return { status: "not_ready", reason: "activation_rejected" };
|
|
316
|
+
}
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
package/device.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export { checkDeviceActivation } from "./device/activation.ts";
|
|
2
|
+
export type { CheckDeviceActivationArgs, TrellisDeviceActivatedStatus, TrellisDeviceActivationRequiredStatus, TrellisDeviceActivationStatus, TrellisDeviceNotReadyStatus, } from "./device/activation.ts";
|
|
3
|
+
import { AsyncResult, UnexpectedError } from "@oatscenter/result";
|
|
4
|
+
import { type ConnectedTrellisClient } from "./client_connect.ts";
|
|
5
|
+
import { type ServiceHealth } from "./service/runtime/health.ts";
|
|
6
|
+
import { type LoggerLike } from "./globals.ts";
|
|
7
|
+
import { TransportError } from "./errors/index.ts";
|
|
8
|
+
import { type CallerRuntime } from "./caller.ts";
|
|
9
|
+
import { type GeneratedParticipant } from "./participant_runtime/participant.ts";
|
|
10
|
+
type DeviceContract = GeneratedParticipant;
|
|
11
|
+
export type TrellisDeviceConnection<TContract extends DeviceContract = DeviceContract> = CallerRuntime<TContract> & {
|
|
12
|
+
readonly health: ServiceHealth;
|
|
13
|
+
} & (TContract extends {
|
|
14
|
+
companion: {
|
|
15
|
+
participant: infer TChild extends GeneratedParticipant;
|
|
16
|
+
availability: infer TAvailability;
|
|
17
|
+
};
|
|
18
|
+
} ? {
|
|
19
|
+
readonly companion: TAvailability extends "required" ? ConnectedTrellisClient<TChild> : ConnectedTrellisClient<TChild> | undefined;
|
|
20
|
+
} : {
|
|
21
|
+
readonly companion?: never;
|
|
22
|
+
});
|
|
23
|
+
export type TrellisDevicePendingActivationState = {
|
|
24
|
+
status: "pending";
|
|
25
|
+
participantId: string;
|
|
26
|
+
publicIdentityKey: string;
|
|
27
|
+
instanceId: string;
|
|
28
|
+
deploymentId: string;
|
|
29
|
+
flowId: string;
|
|
30
|
+
nonce: string;
|
|
31
|
+
activationUrl: string;
|
|
32
|
+
};
|
|
33
|
+
export type TrellisDeviceActivatedActivationState = {
|
|
34
|
+
status: "activated";
|
|
35
|
+
participantId: string;
|
|
36
|
+
publicIdentityKey: string;
|
|
37
|
+
instanceId: string;
|
|
38
|
+
deploymentId: string;
|
|
39
|
+
flowId: string;
|
|
40
|
+
nonce: string;
|
|
41
|
+
activationUrl: string;
|
|
42
|
+
};
|
|
43
|
+
export type TrellisDeviceLocalActivationState = TrellisDevicePendingActivationState | TrellisDeviceActivatedActivationState;
|
|
44
|
+
export type TrellisDeviceActivationSession<TState extends TrellisDeviceLocalActivationState = TrellisDeviceLocalActivationState> = {
|
|
45
|
+
activationUrl: string;
|
|
46
|
+
localState: TState;
|
|
47
|
+
waitForOnlineApproval(opts?: {
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}): Promise<TrellisDeviceActivatedActivationState>;
|
|
50
|
+
acceptConfirmationCode(code: string): Promise<TrellisDeviceActivatedActivationState>;
|
|
51
|
+
};
|
|
52
|
+
export type TrellisDeviceActivationArgs<TContract extends DeviceContract = DeviceContract> = {
|
|
53
|
+
trellisUrl: string;
|
|
54
|
+
participant: TContract;
|
|
55
|
+
rootSecret: Uint8Array | string;
|
|
56
|
+
provisioningSecret?: string;
|
|
57
|
+
};
|
|
58
|
+
/** Provisioned device identity and exact deployment participant binding. */
|
|
59
|
+
export type TrellisDeviceProvisionedIdentity = {
|
|
60
|
+
deploymentId: string;
|
|
61
|
+
instanceId: string;
|
|
62
|
+
principalId: string;
|
|
63
|
+
participantId: string;
|
|
64
|
+
participantDigest: string;
|
|
65
|
+
participantNeedsDigest: string;
|
|
66
|
+
provisioningSecret?: string;
|
|
67
|
+
expectedSecretVersion?: number;
|
|
68
|
+
};
|
|
69
|
+
export type TrellisDeviceResumeActivationArgs<TContract extends DeviceContract = DeviceContract> = TrellisDeviceActivationArgs<TContract> & {
|
|
70
|
+
localState: TrellisDeviceLocalActivationState;
|
|
71
|
+
};
|
|
72
|
+
export type TrellisDeviceConnectArgs<TContract extends DeviceContract = DeviceContract> = {
|
|
73
|
+
trellisUrl: string;
|
|
74
|
+
participant: TContract;
|
|
75
|
+
rootSecret: Uint8Array | string;
|
|
76
|
+
log?: LoggerLike | false;
|
|
77
|
+
};
|
|
78
|
+
export declare const TrellisDevice: {
|
|
79
|
+
connect<TContract extends DeviceContract>(args: TrellisDeviceConnectArgs<TContract>): AsyncResult<TrellisDeviceConnection<TContract>, TransportError | UnexpectedError>;
|
|
80
|
+
};
|