okengine 0.6.1 → 0.8.0
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/AGENTS.md +2 -2
- package/README.md +73 -181
- package/package.json +3 -3
- package/site/content/docs/console/clock.mdx +25 -5
- package/site/content/docs/console/signals.mdx +13 -4
- package/site/content/docs/elements/ai.mdx +29 -2
- package/site/content/docs/elements/channel.mdx +42 -25
- package/site/content/docs/elements/clock.mdx +59 -25
- package/site/content/docs/elements/flow.mdx +8 -2
- package/site/content/docs/elements/gate.mdx +8 -1
- package/site/content/docs/elements/signal.mdx +173 -29
- package/site/content/docs/elements/store.mdx +595 -73
- package/site/content/docs/elements/vault.mdx +15 -5
- package/site/content/docs/get-started/basic-usage.mdx +13 -6
- package/site/content/docs/get-started/installation.mdx +52 -14
- package/site/content/docs/get-started/introduction.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +42 -0
- package/site/content/docs/plugins/phone-number.mdx +78 -17
- package/site/content/docs/plugins/two-factor.mdx +1 -0
- package/site/content/docs/reference/cli.md +32 -2
- package/site/content/docs/reference/configuration.mdx +15 -13
- package/site/content/docs/reference/environment-variables.mdx +32 -18
- package/site/content/docs/reference/errors.mdx +12 -11
- package/site/content/docs/reference/fx.mdx +15 -13
- package/site/content/docs/reference/security.md +3 -1
- package/src/cli/ai-setup/ai-setup.test.ts +144 -0
- package/src/cli/ai-setup/apply.ts +214 -0
- package/src/cli/ai-setup/catalog.ts +263 -0
- package/src/cli/ai-setup/detect-ollama.ts +166 -0
- package/src/cli/ai-setup/index.ts +228 -0
- package/src/cli/ai-setup/prompts.ts +649 -0
- package/src/cli/ai-setup/recommend.test.ts +100 -0
- package/src/cli/ai-setup/recommend.ts +203 -0
- package/src/cli/ai.ts +38 -0
- package/src/cli/db-auto-push.test.ts +6 -1
- package/src/cli/db-auto-push.ts +8 -3
- package/src/cli/db-seed.ts +359 -0
- package/src/cli/db.test.ts +341 -3
- package/src/cli/db.ts +75 -8
- package/src/cli/dev-db-push.test.ts +59 -0
- package/src/cli/dev.test.ts +40 -0
- package/src/cli/dev.ts +55 -1
- package/src/cli/docker-clean.test.ts +179 -0
- package/src/cli/docker-clean.ts +406 -0
- package/src/cli/docker.ts +16 -4
- package/src/cli/ensure-drizzle-config.ts +1 -1
- package/src/cli/hero-meta.test.ts +6 -5
- package/src/cli/hero-meta.ts +7 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/load-config.images.test.ts +22 -0
- package/src/cli/load-config.ts +7 -2
- package/src/cli/openbao-bootstrap.test.ts +1 -0
- package/src/cli/openbao-bootstrap.ts +9 -2
- package/src/cli/registry.ts +116 -2
- package/src/client/live-gap.test.ts +35 -0
- package/src/client/transport.test.ts +21 -0
- package/src/client/transport.ts +27 -5
- package/src/compiler/effects-infer.ts +1 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
- package/src/config/define-config.test.ts +6 -6
- package/src/config/index.ts +5 -1
- package/src/console/server/console.test.ts +45 -0
- package/src/console/server/flows.ts +39 -9
- package/src/console/server/i18n.ts +41 -0
- package/src/console/server/vault.ts +12 -38
- package/src/console/ui/dist/assets/index-ClX0ZCe5.js +10 -0
- package/src/console/ui/dist/assets/{panel-access-BGv45snf.js → panel-access-ri1X9Otj.js} +1 -1
- package/src/console/ui/dist/assets/{panel-ai-B2S7LEii.js → panel-ai-DLHjRoJk.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-D7UJh91v.js → panel-architecture-DI3bQF3J.js} +1 -1
- package/src/console/ui/dist/assets/{panel-channels-9T3ybqRu.js → panel-channels-BDYWX29p.js} +1 -1
- package/src/console/ui/dist/assets/{panel-clock-Cb1UXGRQ.js → panel-clock-i-JpTjVB.js} +1 -1
- package/src/console/ui/dist/assets/{panel-diff-DmYbKWmN.js → panel-diff-CFuWxiXy.js} +1 -1
- package/src/console/ui/dist/assets/{panel-flows-PiHwT55z.js → panel-flows-B8TRhcoe.js} +1 -1
- package/src/console/ui/dist/assets/{panel-gates-BQGYXvjT.js → panel-gates-CfkBgco7.js} +1 -1
- package/src/console/ui/dist/assets/{panel-overview-BBnRO18l.js → panel-overview-DONDzBd2.js} +1 -1
- package/src/console/ui/dist/assets/{panel-plugins-D0PsmVw2.js → panel-plugins-DDJwTehL.js} +1 -1
- package/src/console/ui/dist/assets/{panel-runs-CWuRDe0r.js → panel-runs-D5zf-D9c.js} +1 -1
- package/src/console/ui/dist/assets/{panel-signals-Bbg4ewpP.js → panel-signals-Dsxdu_AR.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-CPCbsDRa.js → panel-store-hy7O8HOs.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-DVAzuA_S.js → panel-traces-CBiAe5go.js} +1 -1
- package/src/console/ui/dist/assets/{panel-vault-D1_MvOmo.js → panel-vault-Za1GyJfM.js} +1 -1
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/shell/components/ui.tsx +5 -1
- package/src/console/ui/shell/setup/Wizard.tsx +26 -5
- package/src/docker/cleanup.test.ts +193 -0
- package/src/docker/cleanup.ts +355 -0
- package/src/docker/docker.test.ts +4 -0
- package/src/docker/index.ts +19 -0
- package/src/docker/recipes/ollama.ts +10 -5
- package/src/drivers/ai-ollama.ts +45 -2
- package/src/drivers/ai-providers.test.ts +31 -0
- package/src/drivers/channel-sently.test.ts +8 -0
- package/src/drivers/channel-taqnyat-mail.ts +34 -0
- package/src/drivers/channel-types.ts +71 -0
- package/src/drivers/clock-postgres.test.ts +258 -0
- package/src/drivers/clock-postgres.ts +410 -0
- package/src/drivers/index.ts +21 -0
- package/src/drivers/journal-postgres.test.ts +175 -0
- package/src/drivers/journal-postgres.ts +492 -0
- package/src/drivers/signal-engine.ts +98 -25
- package/src/drivers/signal-nats.ts +4 -4
- package/src/drivers/signal-postgres.ts +158 -64
- package/src/drivers/signal-redis.ts +4 -4
- package/src/drivers/signal-types.ts +61 -2
- package/src/drivers/vault-driver-removal.test.ts +5 -1
- package/src/elements/channel/runtime.ts +51 -0
- package/src/elements/channel.test.ts +71 -0
- package/src/elements/clock/chaos-child.ts +389 -0
- package/src/elements/clock/chaos.test.ts +204 -0
- package/src/elements/clock/durable.ts +7 -0
- package/src/elements/clock/reconcile.ts +110 -0
- package/src/elements/clock/runtime.ts +13 -0
- package/src/elements/clock.test.ts +164 -2
- package/src/elements/clock.ts +2 -1
- package/src/elements/gate/runtime.ts +6 -0
- package/src/elements/signal/chaos-child.ts +41 -4
- package/src/elements/signal/declare.ts +4 -1
- package/src/elements/signal/delivery-modes.test.ts +179 -0
- package/src/elements/signal/key-ordering.test.ts +306 -0
- package/src/elements/signal/lease-reclaim.test.ts +123 -0
- package/src/elements/signal/optional-emit.test.ts +76 -0
- package/src/elements/signal/order-lifecycle.test.ts +130 -0
- package/src/elements/signal/orphan-messages.test.ts +152 -0
- package/src/elements/signal/runtime.ts +11 -4
- package/src/elements/signal/schema-emit.test.ts +107 -0
- package/src/elements/signal.test.ts +89 -5
- package/src/elements/store/files-fx.ts +104 -0
- package/src/elements/store/files-image.test.ts +251 -0
- package/src/elements/store/files-image.ts +494 -0
- package/src/elements/store/runtime.ts +60 -0
- package/src/elements/store/seed.test.ts +27 -0
- package/src/elements/store/seed.ts +68 -0
- package/src/elements/store/sql-session.test.ts +39 -0
- package/src/elements/store/sql-session.ts +55 -0
- package/src/elements/store/upsert-app.test.ts +103 -0
- package/src/elements/store.ts +29 -0
- package/src/elements/vault/boot-chain.ts +150 -0
- package/src/elements/vault/runtime.ts +8 -0
- package/src/index.ts +15 -0
- package/src/kernel/app.ts +168 -15
- package/src/kernel/boot-bind/channel.test.ts +16 -0
- package/src/kernel/boot-bind/channel.ts +13 -0
- package/src/kernel/boot-bind/clock.ts +63 -7
- package/src/kernel/boot-bind/gate.ts +71 -3
- package/src/kernel/boot-bind/honor-config.test.ts +348 -0
- package/src/kernel/boot-bind/journal.ts +89 -0
- package/src/kernel/boot-bind/signal.ts +64 -7
- package/src/kernel/boot-bind/vault.ts +27 -8
- package/src/kernel/boot.test.ts +6 -4
- package/src/kernel/boot.ts +63 -15
- package/src/kernel/concurrency.ts +1 -1
- package/src/kernel/errors.ts +8 -2
- package/src/kernel/fx.test.ts +19 -0
- package/src/kernel/fx.ts +153 -9
- package/src/kernel/index.ts +6 -0
- package/src/kernel/journal-boot.test.ts +397 -0
- package/src/kernel/journal-suspend.ts +35 -0
- package/src/kernel/journal.test.ts +142 -0
- package/src/kernel/journal.ts +202 -27
- package/src/plugins/auth-methods.security.test.ts +10 -7
- package/src/plugins/phone-number.ts +67 -10
- package/src/plugins/taqnyat.live.test.ts +174 -0
- package/src/runtime/dev-request-log.test.ts +20 -1
- package/src/runtime/dev-request-log.ts +38 -0
- package/src/term.test.ts +15 -0
- package/src/term.ts +8 -3
- package/src/console/ui/dist/assets/index-CjxwRGVv.js +0 -10
package/src/drivers/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ export type {
|
|
|
41
41
|
SignalDriver,
|
|
42
42
|
SignalBus,
|
|
43
43
|
SignalMessage,
|
|
44
|
+
SignalEmitOptions,
|
|
44
45
|
SignalFailureReason,
|
|
45
46
|
DeadLetter,
|
|
46
47
|
SignalTransaction,
|
|
@@ -55,6 +56,8 @@ export type {
|
|
|
55
56
|
SignalDiscardOptions,
|
|
56
57
|
} from "./signal-types.ts";
|
|
57
58
|
|
|
59
|
+
export { SIGNAL_DEFAULT_LEASE_MS } from "./signal-types.ts";
|
|
60
|
+
|
|
58
61
|
export {
|
|
59
62
|
memorySqlDriver,
|
|
60
63
|
memoryKvDriver,
|
|
@@ -103,6 +106,23 @@ export {
|
|
|
103
106
|
type PostgresSignalSql,
|
|
104
107
|
} from "./signal-postgres.ts";
|
|
105
108
|
|
|
109
|
+
export {
|
|
110
|
+
createPostgresCronStore,
|
|
111
|
+
createPostgresCronFake,
|
|
112
|
+
type PostgresCronSql,
|
|
113
|
+
type CreatePostgresCronStoreOptions,
|
|
114
|
+
type BunCronClient,
|
|
115
|
+
} from "./clock-postgres.ts";
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
createPostgresJournalStore,
|
|
119
|
+
createPostgresJournalFake,
|
|
120
|
+
type PostgresJournalSql,
|
|
121
|
+
type PostgresJournalStore,
|
|
122
|
+
type CreatePostgresJournalStoreOptions,
|
|
123
|
+
type BunJournalClient,
|
|
124
|
+
} from "./journal-postgres.ts";
|
|
125
|
+
|
|
106
126
|
export {
|
|
107
127
|
redisSignalDriver,
|
|
108
128
|
openRedisSignal,
|
|
@@ -141,6 +161,7 @@ export { smtpChannelDriver, openSmtpChannel } from "./channel-smtp.ts";
|
|
|
141
161
|
export { resendChannelDriver, openResendChannel } from "./channel-resend.ts";
|
|
142
162
|
export { sndrChannelDriver, openSndrChannel } from "./channel-sndr.ts";
|
|
143
163
|
export { taqnyatChannelDriver, openTaqnyatChannel } from "./channel-taqnyat.ts";
|
|
164
|
+
export { taqnyatMailChannelDriver, openTaqnyatMailChannel } from "./channel-taqnyat-mail.ts";
|
|
144
165
|
export { msegatChannelDriver, openMsegatChannel } from "./channel-msegat.ts";
|
|
145
166
|
export { unifonicChannelDriver, openUnifonicChannel } from "./channel-unifonic.ts";
|
|
146
167
|
export { waCloudChannelDriver, openWaCloudChannel } from "./channel-wa-cloud.ts";
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Postgres JournalStore — unit (fake). Live multi-process boot chaos lives in
|
|
3
|
+
* `src/elements/clock/journal-boot.test.ts` (same LIVE_URL gate as clock).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
|
+
|
|
8
|
+
import type { JournalRun } from "../kernel/journal.ts";
|
|
9
|
+
import { createPostgresJournalFake, createPostgresJournalStore } from "./journal-postgres.ts";
|
|
10
|
+
|
|
11
|
+
function seedRun(patch: Partial<JournalRun> & { id: string }): JournalRun {
|
|
12
|
+
return {
|
|
13
|
+
flow: "charge",
|
|
14
|
+
input: undefined,
|
|
15
|
+
status: "running",
|
|
16
|
+
entries: [],
|
|
17
|
+
createdAt: 1,
|
|
18
|
+
updatedAt: 1,
|
|
19
|
+
...patch,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("postgres JournalStore (fake)", () => {
|
|
24
|
+
test("put / get / list round-trip incl. lease + sleep fields", async () => {
|
|
25
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
26
|
+
await store.put(
|
|
27
|
+
seedRun({
|
|
28
|
+
id: "r1",
|
|
29
|
+
input: { orderId: "o1" },
|
|
30
|
+
entries: [
|
|
31
|
+
{ kind: "step", name: "create-intent", value: { id: "pi_1" }, at: 2 },
|
|
32
|
+
{ kind: "sleep", label: "verify", duration: "7d", wakeAt: 1000, at: 3 },
|
|
33
|
+
],
|
|
34
|
+
status: "sleeping",
|
|
35
|
+
wakeAt: 1000,
|
|
36
|
+
lockedBy: "inst-a",
|
|
37
|
+
leaseExpiresAt: 500,
|
|
38
|
+
output: { ok: true },
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
const row = await store.get("r1");
|
|
42
|
+
expect(row?.flow).toBe("charge");
|
|
43
|
+
expect(row?.input).toEqual({ orderId: "o1" });
|
|
44
|
+
expect(row?.entries).toHaveLength(2);
|
|
45
|
+
expect(row?.status).toBe("sleeping");
|
|
46
|
+
expect(row?.wakeAt).toBe(1000);
|
|
47
|
+
expect(row?.lockedBy).toBe("inst-a");
|
|
48
|
+
expect(row?.leaseExpiresAt).toBe(500);
|
|
49
|
+
expect(row?.output).toEqual({ ok: true });
|
|
50
|
+
expect(await store.list()).toHaveLength(1);
|
|
51
|
+
await store.close();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("acquireLease: exactly one of two racing claimants wins", async () => {
|
|
55
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
56
|
+
await store.put(seedRun({ id: "race" }));
|
|
57
|
+
|
|
58
|
+
const a = store.acquireLease("race", "a", 1_000, 500);
|
|
59
|
+
const b = store.acquireLease("race", "b", 1_000, 500);
|
|
60
|
+
const [wa, wb] = await Promise.all([a, b]);
|
|
61
|
+
expect([wa, wb].filter(Boolean)).toHaveLength(1);
|
|
62
|
+
|
|
63
|
+
const row = await store.get("race");
|
|
64
|
+
expect(row?.lockedBy).toBe(wa ? "a" : "b");
|
|
65
|
+
expect(row?.leaseExpiresAt).toBe(1_500);
|
|
66
|
+
await store.close();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("acquireLease: expired lease is reclaimed lazily (no sweeper)", async () => {
|
|
70
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
71
|
+
await store.put(seedRun({ id: "reclaim", lockedBy: "dead", leaseExpiresAt: 100 }));
|
|
72
|
+
|
|
73
|
+
expect(await store.acquireLease("reclaim", "survivor", 100, 50)).toBe(true);
|
|
74
|
+
const row = await store.get("reclaim");
|
|
75
|
+
expect(row?.lockedBy).toBe("survivor");
|
|
76
|
+
expect(row?.leaseExpiresAt).toBe(150);
|
|
77
|
+
await store.close();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("acquireLease: live lease blocks other instance; same holder renews", async () => {
|
|
81
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
82
|
+
await store.put(seedRun({ id: "held" }));
|
|
83
|
+
expect(await store.acquireLease("held", "leader", 0, 1_000)).toBe(true);
|
|
84
|
+
expect(await store.acquireLease("held", "other", 100, 1_000)).toBe(false);
|
|
85
|
+
expect(await store.acquireLease("held", "leader", 100, 1_000)).toBe(true);
|
|
86
|
+
await store.close();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("claimDueSleep: claims due sleep, skips future + live-leased", async () => {
|
|
90
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
91
|
+
await store.put(seedRun({ id: "future", status: "sleeping", wakeAt: 10_000 }));
|
|
92
|
+
await store.put(
|
|
93
|
+
seedRun({
|
|
94
|
+
id: "leased",
|
|
95
|
+
status: "sleeping",
|
|
96
|
+
wakeAt: 100,
|
|
97
|
+
lockedBy: "other",
|
|
98
|
+
leaseExpiresAt: 9_000,
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
await store.put(seedRun({ id: "due", status: "sleeping", wakeAt: 100 }));
|
|
102
|
+
await store.put(seedRun({ id: "done", status: "completed" }));
|
|
103
|
+
|
|
104
|
+
const claimed = await store.claimDueSleep("me", 1_000, 500);
|
|
105
|
+
expect(claimed?.id).toBe("due");
|
|
106
|
+
const row = await store.get("due");
|
|
107
|
+
expect(row?.lockedBy).toBe("me");
|
|
108
|
+
expect(row?.leaseExpiresAt).toBe(1_500);
|
|
109
|
+
|
|
110
|
+
// Nothing else claimable.
|
|
111
|
+
expect(await store.claimDueSleep("me", 1_000, 500)).toBeUndefined();
|
|
112
|
+
await store.close();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("claimDueSleep: two racing claims hand the run to exactly one instance", async () => {
|
|
116
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
117
|
+
await store.put(seedRun({ id: "due", status: "sleeping", wakeAt: 100 }));
|
|
118
|
+
|
|
119
|
+
const [a, b] = await Promise.all([
|
|
120
|
+
store.claimDueSleep("a", 1_000, 500),
|
|
121
|
+
store.claimDueSleep("b", 1_000, 500),
|
|
122
|
+
]);
|
|
123
|
+
const winners = [a, b].filter((r) => r?.id === "due");
|
|
124
|
+
expect(winners).toHaveLength(1);
|
|
125
|
+
await store.close();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("claimDueSleep: expired lease on a sleeping run is reclaimable", async () => {
|
|
129
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
130
|
+
await store.put(
|
|
131
|
+
seedRun({
|
|
132
|
+
id: "stale",
|
|
133
|
+
status: "sleeping",
|
|
134
|
+
wakeAt: 100,
|
|
135
|
+
lockedBy: "dead",
|
|
136
|
+
leaseExpiresAt: 50,
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
139
|
+
const claimed = await store.claimDueSleep("survivor", 1_000, 500);
|
|
140
|
+
expect(claimed?.id).toBe("stale");
|
|
141
|
+
expect((await store.get("stale"))?.lockedBy).toBe("survivor");
|
|
142
|
+
await store.close();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("listOrphans: running/sleeping without a live lease; never completed", async () => {
|
|
146
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
147
|
+
await store.put(seedRun({ id: "running-unlocked" }));
|
|
148
|
+
await store.put(seedRun({ id: "running-expired", lockedBy: "dead", leaseExpiresAt: 10 }));
|
|
149
|
+
await store.put(seedRun({ id: "running-live", lockedBy: "alive", leaseExpiresAt: 9_000 }));
|
|
150
|
+
await store.put(seedRun({ id: "sleeping-future", status: "sleeping", wakeAt: 99_000 }));
|
|
151
|
+
await store.put(seedRun({ id: "done", status: "completed" }));
|
|
152
|
+
|
|
153
|
+
const orphans = (await store.listOrphans(1_000)).map((r) => r.id);
|
|
154
|
+
expect(orphans).toContain("running-unlocked");
|
|
155
|
+
expect(orphans).toContain("running-expired");
|
|
156
|
+
expect(orphans).toContain("sleeping-future");
|
|
157
|
+
expect(orphans).not.toContain("running-live");
|
|
158
|
+
expect(orphans).not.toContain("done");
|
|
159
|
+
await store.close();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("releaseLease: holder releases; other holder cannot", async () => {
|
|
163
|
+
const store = await createPostgresJournalStore({ sql: createPostgresJournalFake() });
|
|
164
|
+
await store.put(seedRun({ id: "r", lockedBy: "a", leaseExpiresAt: 500 }));
|
|
165
|
+
|
|
166
|
+
await store.releaseLease("r", "b");
|
|
167
|
+
expect((await store.get("r"))?.lockedBy).toBe("a");
|
|
168
|
+
|
|
169
|
+
await store.releaseLease("r", "a");
|
|
170
|
+
const row = await store.get("r");
|
|
171
|
+
expect(row?.lockedBy).toBeUndefined();
|
|
172
|
+
expect(row?.leaseExpiresAt).toBeUndefined();
|
|
173
|
+
await store.close();
|
|
174
|
+
});
|
|
175
|
+
});
|