@frockbot/plugin-applets 0.0.0 → 0.3.13

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.
@@ -0,0 +1,93 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ decodeWorkspaceRootV1,
4
+ workspaceRootKeyV1,
5
+ } from "@frockbot/kernel-contracts";
6
+ import {
7
+ APPLETS_PACKAGE_ID_V1,
8
+ APPLETS_SOURCE_ROOT_ID_V1,
9
+ appletSourceFilePathV1,
10
+ appletSourcePathV1,
11
+ appletsSourceRootV1,
12
+ assertAppletIdV1,
13
+ } from "./root.ts";
14
+
15
+ const APPLET_ID = "pub-user-1.0123456789abcdef0123456789abcdef";
16
+
17
+ describe("the Applets source root", () => {
18
+ test("is the Package-declared root ADR 0022 names", () => {
19
+ expect(appletsSourceRootV1("user-1")).toEqual({
20
+ kind: "package-declared",
21
+ userId: "user-1",
22
+ packageId: "applets",
23
+ rootId: "source",
24
+ });
25
+ expect(APPLETS_PACKAGE_ID_V1).toBe("applets");
26
+ expect(APPLETS_SOURCE_ROOT_ID_V1).toBe("source");
27
+ });
28
+
29
+ test("is a root the kernel decodes and keys, not a shape of its own", () => {
30
+ const root = appletsSourceRootV1("user-1");
31
+ expect(decodeWorkspaceRootV1(root)).toEqual(root);
32
+ expect(workspaceRootKeyV1(root)).toBe(
33
+ "package-declared:user-1:applets:source",
34
+ );
35
+ });
36
+
37
+ test("keys a User's root away from every other User's", () => {
38
+ expect(workspaceRootKeyV1(appletsSourceRootV1("a/b"))).not.toBe(
39
+ workspaceRootKeyV1(appletsSourceRootV1("a%2Fb")),
40
+ );
41
+ });
42
+ });
43
+
44
+ describe("an Applet's source directory", () => {
45
+ test("is `<appletId>/` under the root", () => {
46
+ expect(appletSourcePathV1(APPLET_ID)).toBe(`${APPLET_ID}/`);
47
+ });
48
+
49
+ test("ends in a separator so one id is never a prefix of another", () => {
50
+ // `<id>` and `<id>2` would share a listing prefix; `<id>/` cannot.
51
+ expect(appletSourcePathV1(APPLET_ID).endsWith("/")).toBe(true);
52
+ });
53
+
54
+ test("joins a built artifact onto a Workspace path the kernel accepts", () => {
55
+ expect(
56
+ appletSourceFilePathV1("user-1", APPLET_ID, "dist/server.js"),
57
+ ).toEqual({
58
+ root: appletsSourceRootV1("user-1"),
59
+ path: `${APPLET_ID}/dist/server.js`,
60
+ });
61
+ });
62
+ });
63
+
64
+ describe("the Applet id shape", () => {
65
+ test("accepts the ADR 0015 share-id shape", () => {
66
+ expect(assertAppletIdV1(APPLET_ID)).toBe(APPLET_ID);
67
+ });
68
+
69
+ test("refuses an id that is not `<publicUserId>.<random>`", () => {
70
+ for (const invalid of [
71
+ "no-separator",
72
+ ".0123456789abcdef0123456789abcdef",
73
+ "pub-user-1.",
74
+ "pub-user-1.short",
75
+ "pub-user-1.0123456789ABCDEF0123456789ABCDEF",
76
+ "pub user 1.0123456789abcdef0123456789abcdef",
77
+ 42,
78
+ ]) {
79
+ expect(() => assertAppletIdV1(invalid)).toThrow("applet id is invalid");
80
+ }
81
+ });
82
+
83
+ test("refuses a traversal rather than folding it into another directory", () => {
84
+ // The id is a directory on a real filesystem the sync reconciles. Folding
85
+ // would silently point two Applets at one source tree.
86
+ expect(() => appletSourcePathV1("../escape")).toThrow(
87
+ "applet id is invalid",
88
+ );
89
+ expect(() => appletSourcePathV1(`${APPLET_ID}/../other`)).toThrow(
90
+ "applet id is invalid",
91
+ );
92
+ });
93
+ });
package/src/root.ts ADDED
@@ -0,0 +1,111 @@
1
+ // Where an Applet's source lives, and why there.
2
+ //
3
+ // ADR 0022 decision 7: "Applet source lives under a `package-declared` durable
4
+ // root of the Applets Package, `applets/<appletId>/`, synchronized by the
5
+ // durable-root sync of ADR 0013." An Applet is *written* on the Computer and
6
+ // *run* in the loader, so its source has to be a real file a Bot can open with
7
+ // ordinary file tools, type-check, lint, and preview — and it has to survive
8
+ // hibernation, cold start, host migration, and an image rebuild. That is the
9
+ // definition of a durable root, and `package-declared` is the only kind a
10
+ // Package declares for itself (`kernel-contracts/src/workspace.ts`).
11
+ //
12
+ // The root is User-scoped, like every `package-declared` root: Applets are
13
+ // account-wide (ADR 0022 decision 3, plan D2), so one User's Bots share the
14
+ // root and an Applet a Bot wrote is an Applet every Bot of that User can edit.
15
+ // It is read-write on the Computer — unlike Memory and the User instruction
16
+ // root, whose single writer is a Package — because writing source with a shell
17
+ // is exactly what the Bot is meant to do here.
18
+ //
19
+ // The published artifact is *not* what runs. `applet build` writes
20
+ // `<appletId>/dist/` inside this root, the sync pushes it to object storage,
21
+ // and publish reads the built bytes back through the Workspace file surface
22
+ // (`syncWorkspaceRootNowV1` in `@frockbot/plugin-computer/agent` is the one
23
+ // sanctioned way to make that push happen outside the Turn's own policy). No
24
+ // credential ever reaches the Computer for the publish.
25
+ import {
26
+ normalizeWorkspaceRelativePathV1,
27
+ type WorkspacePathV1,
28
+ type WorkspaceRootV1,
29
+ } from "@frockbot/kernel-contracts";
30
+ // The Applet id shape is ADR 0015's share id, `<publicUserId>.<random>`, and
31
+ // this is its one validator. Reused rather than re-expressed: a second regex
32
+ // for the same shape is a second answer to "is this id well formed", and the
33
+ // difference between the two would be found by a path that accepted an id the
34
+ // share surface refuses. The name says `template` because that is where the
35
+ // shape was first needed, not because it is about templates.
36
+ import {
37
+ parseTemplateShareIdV1,
38
+ TemplateDecodeError,
39
+ } from "@frockbot/template-core";
40
+
41
+ /** The Package id the declared root belongs to. Matches `frockbot.json`. */
42
+ export const APPLETS_PACKAGE_ID_V1 = "applets";
43
+ /** The declared root Applet source is written under. */
44
+ export const APPLETS_SOURCE_ROOT_ID_V1 = "source";
45
+
46
+ /**
47
+ * The Package-declared Workspace root Applet source lives in.
48
+ *
49
+ * On a Fly Sprite this resolves to
50
+ * `/home/box/agent-data/user-packages/applets/source` — the layout's one
51
+ * `package-declared` template with `{package}` and `{root}` substituted, so no
52
+ * Computer Package learns that Applets exist.
53
+ */
54
+ export function appletsSourceRootV1(userId: string): WorkspaceRootV1 {
55
+ return {
56
+ kind: "package-declared",
57
+ userId,
58
+ packageId: APPLETS_PACKAGE_ID_V1,
59
+ rootId: APPLETS_SOURCE_ROOT_ID_V1,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * The Applet id in an id-shaped string, or a thrown error.
65
+ *
66
+ * An Applet id is a path segment on a real filesystem and a directory the sync
67
+ * reconciles, so it is validated rather than folded: an id that is not the
68
+ * shape the kernel mints is a caller's bug, and quietly rewriting it into a
69
+ * different directory would make two Applets share one source tree.
70
+ */
71
+ export function assertAppletIdV1(appletId: unknown): string {
72
+ try {
73
+ parseTemplateShareIdV1(appletId);
74
+ } catch (error) {
75
+ throw new Error(
76
+ error instanceof TemplateDecodeError
77
+ ? "applet id is invalid"
78
+ : String(error),
79
+ );
80
+ }
81
+ return appletId as string;
82
+ }
83
+
84
+ /**
85
+ * One Applet's source directory inside the root, as a relative prefix.
86
+ *
87
+ * Trailing slash, because it is a directory prefix and every caller either
88
+ * lists under it or joins a file onto it — `applets/<id>` and `applets/<id>2`
89
+ * would otherwise share a prefix.
90
+ */
91
+ export function appletSourcePathV1(appletId: string): string {
92
+ return `${assertAppletIdV1(appletId)}/`;
93
+ }
94
+
95
+ /** One file inside an Applet's source directory, as a Workspace path. */
96
+ export function appletSourceFilePathV1(
97
+ userId: string,
98
+ appletId: string,
99
+ relativePath: string,
100
+ ): WorkspacePathV1 {
101
+ return {
102
+ root: appletsSourceRootV1(userId),
103
+ path: normalizeWorkspaceRelativePathV1(
104
+ `${appletSourcePathV1(appletId)}${relativePath}`,
105
+ "applet source path",
106
+ ),
107
+ };
108
+ }
109
+
110
+ /** Where `applet build` leaves the artifacts publish reads. */
111
+ export const APPLET_DIST_DIRECTORY_V1 = "dist";
@@ -0,0 +1,37 @@
1
+ // Generated by scripts/build-applets-package.ts. Do not edit.
2
+ //
3
+ // The Applets SDK's scaffold, as strings. `applet_create` writes these
4
+ // through `ctx.workspace.write` from inside a Bot isolate, which has no
5
+ // filesystem and no way to read this repository, so the template travels
6
+ // in the artifact rather than beside it. Editing
7
+ // `packages/applet-sdk/template/` and rerunning the build is the only way
8
+ // to change what a new Applet starts as.
9
+ //
10
+ // The bodies are base64 because the Package bundler refuses a module
11
+ // whose text contains an import specifier it cannot resolve, and Applet
12
+ // source contains several. `package.ts` decodes them.
13
+ export const APPLET_TEMPLATE_FILES_V1: ReadonlyArray<{
14
+ path: string;
15
+ base64: string;
16
+ }> = [
17
+ {
18
+ path: "README.md",
19
+ base64:
20
+ "IyBfX0FQUExFVF9OQU1FX18KCkEgRnJvY2tCb3QgQXBwbGV0LiBUd28gZmlsZXMgYXJlIHlvdXJzOgoKfCBGaWxlICAgICAgICB8IFdoYXQgaXQgb3ducyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAtLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwKfCBgc2VydmVyLnRzYCB8IHRoZSB0YWJsZXMgKHN0YXRlIHRoYXQgc3Vydml2ZXMgZXZlcnkgY29kZSBjaGFuZ2UpIGFuZCB0aGUgdG9vbHMgQm90cyBjYWxsIHwKfCBgdWkudHN4YCAgICB8IHRoZSBwYWdlIHRoZSBVc2VyIHNlZXMgYmVzaWRlIHRoZSBjb252ZXJzYXRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKCiMjIFRoZSBsb29wCgpgYGBzaAphcHBsZXQgY2hlY2sgIyB0eXBlLWNoZWNrIGFuZCBsaW50OyBldmVyeSBwcm9ibGVtIHByaW50cyBhcyBwYXRoOmxpbmU6Y29sIG1lc3NhZ2UKYXBwbGV0IGJ1aWxkICMgZGlzdC9zZXJ2ZXIuanMsIGRpc3QvdWkuaHRtbCwgZGlzdC9tYW5pZmVzdC5qc29uCmFwcGxldCBkZXYgICAjIHNlcnZlcyB0aGUgYnVpbHQgQXBwbGV0OyBwcmludHMgYSBVUkwsIG9wZW5zIG5vdGhpbmcKYGBgCgpPcGVuIHRoZSBwcmludGVkIFVSTCBpbiB0aGUgQ29tcHV0ZXIncyBicm93c2VyIHRvIGxvb2sgYXQgaXQuIFB1Ymxpc2ggd2l0aApgYXBwbGV0X3B1Ymxpc2hgIG9uY2UgYGFwcGxldCBjaGVja2AgaXMgY2xlYW4uCgojIyBSdWxlcyB0aGUgbGludGVyIGVuZm9yY2VzCgotIENvbG91cnMgY29tZSBmcm9tIHRoZSBuaW5lIGAtLWZyb2NrYm90LSpgIHRoZW1lIHRva2Vucy4gVGhlIGtpdCdzIGNvbXBvbmVudHMKICBhbHJlYWR5IHVzZSB0aGVtOyBuZXZlciB3cml0ZSBgI2hleGAsIGByZ2IoLi4uKWAsIG9yIGEgY29sb3VyIG5hbWUuCi0gTm8gYGZldGNoYCwgYFhNTEh0dHBSZXF1ZXN0YCwgb3IgYFdlYlNvY2tldGAuIFRoZSBBcHBsZXQgaGFzIG5vIG91dGJvdW5kCiAgbmV0d29yazogcmVhY2ggdGhlIHdvcmxkIHRocm91Z2ggYSB0b29sIG9uIHRoZSBzZXJ2ZXIuCi0gSW1wb3J0IG9ubHkgZnJvbSBgQGZyb2NrYm90L2FwcGxldC1zZGsvKmAsIGByZWFjdGAsIGFuZCB5b3VyIG93biBmaWxlcy4KLSBEZWNsYXJlIHRhYmxlcyB3aXRoIGB0YWJsZSh7IC4uLiB9KWAgYW5kIHRvb2xzIHdpdGggYHRoaXMudG9vbCh7IC4uLiB9LCBmbilgLgoKIyMgQ2hhbmdpbmcgdGhlIHNjaGVtYQoKQWRkIGEgY29sdW1uIHdpdGggYC5kZWZhdWx0KC4uLilgIG9yIGAub3B0aW9uYWwoKWAgYW5kIHRoZSBTREsgYWRkcyBpdCBvbiB0aGUKbmV4dCBtb3VudCwga2VlcGluZyB0aGUgcm93cy4gRm9yIGFueXRoaW5nIGVsc2Ug4oCUIHJlbmFtaW5nLCByZXdyaXRpbmcgdmFsdWVzIOKAlApvdmVycmlkZSBgbWlncmF0ZShmcm9tKWAgb24gdGhlIGNsYXNzOyBpdCBydW5zIG9uY2UsIGJlZm9yZSB0aGUgQXBwbGV0IHNlcnZlcwphbnl0aGluZywgYW5kIHRocm93aW5nIGZhaWxzIHRoZSBtb3VudCBiYWNrIHRvIHRoZSBsYXN0IGtub3duLWdvb2QgZ2VuZXJhdGlvbi4KClRoZSBraXQncyBjb21wb25lbnRzIGFuZCB0aGVpciBwcm9wcyBhcmUgZG9jdW1lbnRlZCBpbiB0aGUgQXBwbGV0cyBTa2lsbC4K",
21
+ },
22
+ {
23
+ path: "applet.json",
24
+ base64:
25
+ "ewogICJpZCI6ICJfX0FQUExFVF9JRF9fIiwKICAiZGlzcGxheU5hbWUiOiAiX19BUFBMRVRfTkFNRV9fIiwKICAiY29udHJhY3QiOiAxCn0K",
26
+ },
27
+ {
28
+ path: "ui.tsx",
29
+ base64:
30
+ "aW1wb3J0IHsgdXNlU3RhdGUgfSBmcm9tICJyZWFjdCI7CmltcG9ydCB7IGNyZWF0ZUFwcGxldCwgbW91bnQsIG5ld0lkIH0gZnJvbSAiQGZyb2NrYm90L2FwcGxldC1zZGsvY2xpZW50IjsKaW1wb3J0IHsKICBCdXR0b24sCiAgQ2hlY2tib3gsCiAgRW1wdHlTdGF0ZSwKICBJbnB1dCwKICBMaXN0LAogIExpc3RJdGVtLAogIFN0YWNrLAogIFRleHQsCiAgVG9vbGJhciwKfSBmcm9tICJAZnJvY2tib3QvYXBwbGV0LXNkay9raXQiOwoKaW1wb3J0IHR5cGUgVG9kb0FwcGxldCBmcm9tICIuL3NlcnZlciI7CgovKioKICogVGhlIHBhZ2UgaGFsZiBvZiBfX0FQUExFVF9OQU1FX18uCiAqCiAqIGBjcmVhdGVBcHBsZXRgIGNvbm5lY3RzIHdoZW4gdGhlIGhvc3Qgc2VuZHMgaXRzIGBpbml0YCBtZXNzYWdlLCBzbyB0aGVyZSBpcwogKiBubyBsb2FkaW5nIHdpcmluZyB0byB3cml0ZS4gRXZlcnkgbXV0YXRpb24gaXMgb3B0aW1pc3RpYzogdGhlIHJvdyBhcHBlYXJzIGF0CiAqIG9uY2UgYW5kIHJvbGxzIGJhY2sgb24gaXRzIG93biBpZiB0aGUgc2VydmVyIHJlamVjdHMgaXQuCiAqLwpjb25zdCBhcHBsZXQgPSBjcmVhdGVBcHBsZXQ8VG9kb0FwcGxldD4oKTsKCmZ1bmN0aW9uIEFwcCgpIHsKICBjb25zdCBbZHJhZnQsIHNldERyYWZ0XSA9IHVzZVN0YXRlKCIiKTsKICBjb25zdCB7IHN0YXR1cyB9ID0gYXBwbGV0LnVzZUFwcGxldCgpOwogIGNvbnN0IHsgZGF0YTogdG9kb3MgfSA9IGFwcGxldC51c2VMaXZlUXVlcnkoKHF1ZXJ5KSA9PgogICAgcXVlcnkKICAgICAgLmZyb20oeyB0b2RvOiBhcHBsZXQudGFibGVzLnRvZG9zIH0pCiAgICAgIC5vcmRlckJ5KCh7IHRvZG8gfSkgPT4gdG9kby5jcmVhdGVkQXQpLAogICk7CgogIGNvbnN0IGFkZCA9ICgpID0+IHsKICAgIGNvbnN0IHRpdGxlID0gZHJhZnQudHJpbSgpOwogICAgaWYgKHRpdGxlID09PSAiIikgcmV0dXJuOwogICAgYXBwbGV0LnRhYmxlcy50b2Rvcy5pbnNlcnQoewogICAgICBpZDogbmV3SWQoKSwKICAgICAgdGl0bGUsCiAgICAgIGRvbmU6IGZhbHNlLAogICAgICBjcmVhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwKICAgIH0pOwogICAgc2V0RHJhZnQoIiIpOwogIH07CgogIHJldHVybiAoCiAgICA8U3RhY2sgcm9vdCBnYXA9ImxhcmdlIj4KICAgICAgPFRvb2xiYXIKICAgICAgICBlbmQ9ewogICAgICAgICAgPFRleHQgc2l6ZT0ic21hbGwiIHRvbmU9Im11dGVkIj4KICAgICAgICAgICAge3N0YXR1c30KICAgICAgICAgIDwvVGV4dD4KICAgICAgICB9CiAgICAgID4KICAgICAgICA8VGV4dCBzaXplPSJ0aXRsZSI+X19BUFBMRVRfTkFNRV9fPC9UZXh0PgogICAgICA8L1Rvb2xiYXI+CgogICAgICA8U3RhY2sgZGlyZWN0aW9uPSJyb3ciIGdhcD0ic21hbGwiIGFsaWduPSJlbmQiPgogICAgICAgIDxJbnB1dAogICAgICAgICAgbGFiZWw9Ik5ldyB0b2RvIgogICAgICAgICAgdmFsdWU9e2RyYWZ0fQogICAgICAgICAgcGxhY2Vob2xkZXI9IkJ1eSBtaWxrIgogICAgICAgICAgb25WYWx1ZUNoYW5nZT17c2V0RHJhZnR9CiAgICAgICAgICBvbktleURvd249eyhldmVudCkgPT4gewogICAgICAgICAgICBpZiAoZXZlbnQua2V5ID09PSAiRW50ZXIiKSBhZGQoKTsKICAgICAgICAgIH19CiAgICAgICAgLz4KICAgICAgICA8QnV0dG9uIHZhcmlhbnQ9InByaW1hcnkiIG9uQ2xpY2s9e2FkZH0+CiAgICAgICAgICBBZGQKICAgICAgICA8L0J1dHRvbj4KICAgICAgPC9TdGFjaz4KCiAgICAgIHt0b2Rvcy5sZW5ndGggPT09IDAgPyAoCiAgICAgICAgPEVtcHR5U3RhdGUKICAgICAgICAgIHRpdGxlPSJOb3RoaW5nIHlldCIKICAgICAgICAgIGRlc2NyaXB0aW9uPSJBZGQgeW91ciBmaXJzdCB0b2RvIGFib3ZlLiIKICAgICAgICAvPgogICAgICApIDogKAogICAgICAgIDxMaXN0PgogICAgICAgICAge3RvZG9zLm1hcCgodG9kbykgPT4gKAogICAgICAgICAgICA8TGlzdEl0ZW0KICAgICAgICAgICAgICBrZXk9e3RvZG8uaWR9CiAgICAgICAgICAgICAgc3RhcnQ9ewogICAgICAgICAgICAgICAgPENoZWNrYm94CiAgICAgICAgICAgICAgICAgIGNoZWNrZWQ9e3RvZG8uZG9uZX0KICAgICAgICAgICAgICAgICAgYXJpYUxhYmVsPXtgTWFyayAiJHt0b2RvLnRpdGxlfSIgZG9uZWB9CiAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlPXsoZG9uZSkgPT4KICAgICAgICAgICAgICAgICAgICBhcHBsZXQudGFibGVzLnRvZG9zLnVwZGF0ZSh0b2RvLmlkLCAoZHJhZnRSb3cpID0+IHsKICAgICAgICAgICAgICAgICAgICAgIGRyYWZ0Um93LmRvbmUgPSBkb25lOwogICAgICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8+CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGVuZD17CiAgICAgICAgICAgICAgICA8QnV0dG9uCiAgICAgICAgICAgICAgICAgIHZhcmlhbnQ9Imdob3N0IgogICAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiBhcHBsZXQudGFibGVzLnRvZG9zLmRlbGV0ZSh0b2RvLmlkKX0KICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgRGVsZXRlCiAgICAgICAgICAgICAgICA8L0J1dHRvbj4KICAgICAgICAgICAgICB9CiAgICAgICAgICAgID4KICAgICAgICAgICAgICA8VGV4dCB0b25lPXt0b2RvLmRvbmUgPyAibXV0ZWQiIDogImRlZmF1bHQifT57dG9kby50aXRsZX08L1RleHQ+CiAgICAgICAgICAgIDwvTGlzdEl0ZW0+CiAgICAgICAgICApKX0KICAgICAgICA8L0xpc3Q+CiAgICAgICl9CiAgICA8L1N0YWNrPgogICk7Cn0KCm1vdW50KDxBcHAgLz4pOwo=",
31
+ },
32
+ {
33
+ path: "server.ts",
34
+ base64:
35
+ "aW1wb3J0IHsgQXBwbGV0LCB0LCB0YWJsZSB9IGZyb20gIkBmcm9ja2JvdC9hcHBsZXQtc2RrL3NlcnZlciI7CgovKioKICogVGhlIHNjaGVtYS4gSXQgYmVjb21lcyB0aGUgU1FMaXRlIHRhYmxlcywgdGhlIHdpcmUgZm9ybWF0LCBhbmQgdGhlIGNsaWVudCdzCiAqIGNvbGxlY3Rpb25zLCBhbmQgaXQgc3Vydml2ZXMgZXZlcnkgcHVibGlzaDogY2hhbmdpbmcgdGhpcyBmaWxlJ3MgY29kZSBuZXZlcgogKiBjbGVhcnMgdGhlIHJvd3MuCiAqLwpjb25zdCB0YWJsZXMgPSB7CiAgdG9kb3M6IHRhYmxlKHsKICAgIGlkOiB0LmlkKCksCiAgICB0aXRsZTogdC50ZXh0KCksCiAgICBkb25lOiB0LmJvb2xlYW4oKS5kZWZhdWx0KGZhbHNlKSwKICAgIGNyZWF0ZWRBdDogdC50aW1lc3RhbXAoKSwKICB9KSwKfTsKCi8qKgogKiBUaGUgc2VydmVyIGhhbGYgb2YgX19BUFBMRVRfTkFNRV9fLgogKgogKiBgdG9vbHNgIGlzIHdoYXQgZXZlcnkgQm90IG9mIHRoaXMgVXNlciBjYW4gY2FsbC4gYHRoaXMuZGJgIGlzIHRoZSBvbmx5IHdheQogKiB0byByZWFkIG9yIHdyaXRlLCBhbmQgZWFjaCBjYWxsIGlzIGF0b21pYy4KICovCmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRvZG9BcHBsZXQgZXh0ZW5kcyBBcHBsZXQ8dHlwZW9mIHRhYmxlcz4gewogIHRhYmxlcyA9IHRhYmxlczsKCiAgdG9vbHMgPSB7CiAgICBhZGRfdG9kbzogdGhpcy50b29sKAogICAgICB7IGRlc2NyaXB0aW9uOiAiQWRkIGEgdG9kbyB0byB0aGUgbGlzdCIsIGlucHV0OiB7IHRpdGxlOiB0LnRleHQoKSB9IH0sCiAgICAgICh7IHRpdGxlIH0pID0+IHsKICAgICAgICB0aGlzLmRiLnRvZG9zLmluc2VydCh7IHRpdGxlLCBjcmVhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSB9KTsKICAgICAgICByZXR1cm4gYEFkZGVkICIke3RpdGxlfSIuYDsKICAgICAgfSwKICAgICksCiAgICBsaXN0X3RvZG9zOiB0aGlzLnRvb2woCiAgICAgIHsgZGVzY3JpcHRpb246ICJMaXN0IHRoZSB0b2Rvcywgb3BlbiBvbmVzIGZpcnN0IiwgaW5wdXQ6IHt9IH0sCiAgICAgICgpID0+IHsKICAgICAgICBjb25zdCB0b2RvcyA9IHRoaXMuZGIudG9kb3Muc2VsZWN0KCk7CiAgICAgICAgaWYgKHRvZG9zLmxlbmd0aCA9PT0gMCkgcmV0dXJuICJUaGUgbGlzdCBpcyBlbXB0eS4iOwogICAgICAgIHJldHVybiB0b2RvcwogICAgICAgICAgLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBOdW1iZXIobGVmdC5kb25lKSAtIE51bWJlcihyaWdodC5kb25lKSkKICAgICAgICAgIC5tYXAoKHRvZG8pID0+IGAke3RvZG8uZG9uZSA/ICJbeF0iIDogIlsgXSJ9ICR7dG9kby50aXRsZX1gKQogICAgICAgICAgLmpvaW4oIlxuIik7CiAgICAgIH0sCiAgICApLAogIH07Cn0K",
36
+ },
37
+ ];
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # @frockbot/plugin-applets
2
-
3
- Placeholder reserving this name. See https://github.com/timoconnellaus/frockbot.