@fungi.computer/agar 0.0.0-stage → 0.0.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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +766 -2
  3. package/dist/agent-message-meta.d.ts +74 -0
  4. package/dist/agent-message-meta.js +63 -0
  5. package/dist/agents.d.ts +170 -0
  6. package/dist/agents.js +218 -0
  7. package/dist/app-build-contract.d.ts +43 -0
  8. package/dist/app-build-contract.js +24 -0
  9. package/dist/apps.d.ts +66 -0
  10. package/dist/apps.js +47 -0
  11. package/dist/backend-declaration.d.ts +6 -0
  12. package/dist/backend-declaration.js +65 -0
  13. package/dist/backend-definition.d.ts +88 -0
  14. package/dist/backend-definition.js +158 -0
  15. package/dist/backend-refusal.d.ts +10 -0
  16. package/dist/backend-refusal.js +10 -0
  17. package/dist/backend.d.ts +30 -0
  18. package/dist/backend.js +28 -0
  19. package/dist/capabilities.d.ts +30 -0
  20. package/dist/capabilities.js +50 -0
  21. package/dist/channels.d.ts +142 -0
  22. package/dist/channels.js +97 -0
  23. package/dist/commands.d.ts +33 -0
  24. package/dist/commands.js +46 -0
  25. package/dist/computer-contracts.d.ts +73 -0
  26. package/dist/computer-contracts.js +57 -0
  27. package/dist/computer.d.ts +294 -0
  28. package/dist/computer.js +319 -0
  29. package/dist/connect.d.ts +11 -0
  30. package/dist/connect.js +211 -0
  31. package/dist/errors.d.ts +34 -0
  32. package/dist/errors.js +106 -0
  33. package/dist/failure.d.ts +2 -0
  34. package/dist/failure.js +9 -0
  35. package/dist/files.d.ts +25 -0
  36. package/dist/files.js +84 -0
  37. package/dist/game-servers.d.ts +530 -0
  38. package/dist/game-servers.js +244 -0
  39. package/dist/gills.d.ts +43 -0
  40. package/dist/gills.js +174 -0
  41. package/dist/git-commit.d.ts +143 -0
  42. package/dist/git-commit.js +251 -0
  43. package/dist/git-rpc.d.ts +310 -0
  44. package/dist/git-rpc.js +166 -0
  45. package/dist/git-steps.d.ts +579 -0
  46. package/dist/git-steps.js +804 -0
  47. package/dist/git-wire.d.ts +33 -0
  48. package/dist/git-wire.js +240 -0
  49. package/dist/git.d.ts +322 -0
  50. package/dist/git.js +98 -0
  51. package/dist/host.d.ts +97 -0
  52. package/dist/host.js +732 -0
  53. package/dist/inbox.d.ts +99 -0
  54. package/dist/inbox.js +184 -0
  55. package/dist/index.d.ts +31 -0
  56. package/dist/index.js +15 -0
  57. package/dist/inference.d.ts +17 -0
  58. package/dist/inference.js +115 -0
  59. package/dist/internal/app-error.d.ts +8 -0
  60. package/dist/internal/app-error.js +36 -0
  61. package/dist/internal/app-session.d.ts +8 -0
  62. package/dist/internal/app-session.js +551 -0
  63. package/dist/internal/back-inputs.d.ts +22 -0
  64. package/dist/internal/back-inputs.js +93 -0
  65. package/dist/internal/browser-bridge.d.ts +30 -0
  66. package/dist/internal/browser-bridge.js +203 -0
  67. package/dist/internal/capabilities.d.ts +13 -0
  68. package/dist/internal/capabilities.js +138 -0
  69. package/dist/internal/commands.d.ts +9 -0
  70. package/dist/internal/commands.js +257 -0
  71. package/dist/internal/disconnect-host.d.ts +7 -0
  72. package/dist/internal/disconnect-host.js +19 -0
  73. package/dist/internal/git-edit-tree.d.ts +6 -0
  74. package/dist/internal/git-edit-tree.js +46 -0
  75. package/dist/internal/memory-fs.d.ts +39 -0
  76. package/dist/internal/memory-fs.js +154 -0
  77. package/dist/internal/protocol.d.ts +116 -0
  78. package/dist/internal/protocol.js +6 -0
  79. package/dist/internal/query-feed.d.ts +23 -0
  80. package/dist/internal/query-feed.js +111 -0
  81. package/dist/internal/result.d.ts +22 -0
  82. package/dist/internal/result.js +61 -0
  83. package/dist/internal/rpc-contract.d.ts +24 -0
  84. package/dist/internal/rpc-contract.js +78 -0
  85. package/dist/internal/schemas.d.ts +307 -0
  86. package/dist/internal/schemas.js +524 -0
  87. package/dist/internal/store.d.ts +8 -0
  88. package/dist/internal/store.js +30 -0
  89. package/dist/internal/terminal-gate.d.ts +17 -0
  90. package/dist/internal/terminal-gate.js +94 -0
  91. package/dist/lifecycle.d.ts +44 -0
  92. package/dist/lifecycle.js +1 -0
  93. package/dist/marketplace.d.ts +159 -0
  94. package/dist/marketplace.js +102 -0
  95. package/dist/media-json.d.ts +181 -0
  96. package/dist/media-json.js +204 -0
  97. package/dist/media-library.d.ts +11 -0
  98. package/dist/media-library.js +15 -0
  99. package/dist/media-request-id.d.ts +7 -0
  100. package/dist/media-request-id.js +16 -0
  101. package/dist/media.d.ts +354 -0
  102. package/dist/media.js +654 -0
  103. package/dist/method-refusal.d.ts +64 -0
  104. package/dist/method-refusal.js +48 -0
  105. package/dist/pending.d.ts +10 -0
  106. package/dist/pending.js +10 -0
  107. package/dist/query.d.ts +76 -0
  108. package/dist/query.js +195 -0
  109. package/dist/react-mount.d.ts +23 -0
  110. package/dist/react-mount.js +108 -0
  111. package/dist/react.d.ts +41 -0
  112. package/dist/react.js +111 -0
  113. package/dist/read-copy.d.ts +103 -0
  114. package/dist/read-copy.js +195 -0
  115. package/dist/roles/files.d.ts +295 -0
  116. package/dist/roles/files.js +184 -0
  117. package/dist/root.d.ts +21 -0
  118. package/dist/root.js +1 -0
  119. package/dist/rpc.d.ts +1 -0
  120. package/dist/rpc.js +1 -0
  121. package/dist/status.d.ts +17 -0
  122. package/dist/status.js +50 -0
  123. package/dist/storage-wire.d.ts +167 -0
  124. package/dist/storage-wire.js +115 -0
  125. package/dist/storage.d.ts +72 -0
  126. package/dist/storage.js +143 -0
  127. package/dist/store.d.ts +11 -0
  128. package/dist/store.js +1 -0
  129. package/dist/test-kit/git.d.ts +31 -0
  130. package/dist/test-kit/git.js +174 -0
  131. package/dist/ui.d.ts +169 -0
  132. package/dist/ui.js +10 -0
  133. package/dist/window.d.ts +41 -0
  134. package/dist/window.js +15 -0
  135. package/dist/world.d.ts +16 -0
  136. package/dist/world.js +17 -0
  137. package/docs/api/README.md +28 -0
  138. package/docs/api/app-build-contract.md +113 -0
  139. package/docs/api/backend-declaration.md +62 -0
  140. package/docs/api/backend-definition.md +215 -0
  141. package/docs/api/backend.md +269 -0
  142. package/docs/api/errors.md +169 -0
  143. package/docs/api/files.md +91 -0
  144. package/docs/api/gills.md +164 -0
  145. package/docs/api/git-commit.md +279 -0
  146. package/docs/api/git-rpc.md +243 -0
  147. package/docs/api/git-steps.md +1010 -0
  148. package/docs/api/git-wire.md +197 -0
  149. package/docs/api/git.md +579 -0
  150. package/docs/api/index.md +2880 -0
  151. package/docs/api/media-json.md +507 -0
  152. package/docs/api/media-request-id.md +32 -0
  153. package/docs/api/modules.md +32 -0
  154. package/docs/api/query.md +253 -0
  155. package/docs/api/react.md +216 -0
  156. package/docs/api/read-copy.md +204 -0
  157. package/docs/api/rpc.md +128 -0
  158. package/docs/api/storage.md +620 -0
  159. package/package.json +197 -3
@@ -0,0 +1,167 @@
1
+ import * as Schema from "effect/Schema";
2
+ import { appStorageKeyNameSchema } from "@fungi.computer/puffball/app";
3
+ export { appStorageKeyNameSchema };
4
+ /**
5
+ * Storage error codes the host and client agree on: invalid input, an
6
+ * undeclared key, a scope this App never declared, a member-only action
7
+ * tried without a member, a value or quota that is too large, a write
8
+ * conflict, or a transient host failure.
9
+ */
10
+ export declare const appStorageErrorCodes: readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"];
11
+ /** Validates that a value is one of the known storage error codes. */
12
+ export declare const appStorageErrorCodeSchema: Schema.Literals<readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"]>;
13
+ /**
14
+ * Thrown by the storage client when a read, write, reset, or watch is
15
+ * rejected by the host; `code` identifies why.
16
+ */
17
+ export declare class AppStorageError extends Error {
18
+ readonly code: typeof appStorageErrorCodeSchema.Type;
19
+ constructor(code: typeof appStorageErrorCodeSchema.Type, options?: ErrorOptions);
20
+ }
21
+ /**
22
+ * Validates the resolved shape of a storage key: its merged value, which
23
+ * layer it came from, the raw team and member layers it was merged from,
24
+ * and whether this App may write to the team layer.
25
+ */
26
+ export declare const resolvedAppStorageSchema: Schema.Struct<{
27
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
28
+ readonly source: Schema.Literals<readonly ["member", "team", "none"]>;
29
+ readonly team: Schema.NullOr<Schema.Struct<{
30
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
31
+ readonly revision: Schema.Int;
32
+ }>>;
33
+ readonly member: Schema.NullOr<Schema.Struct<{
34
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
35
+ readonly revision: Schema.Int;
36
+ }>>;
37
+ readonly canWriteTeam: Schema.Boolean;
38
+ }>;
39
+ /**
40
+ * The resolved value for a storage key, as returned by `read`: the merged
41
+ * value, which layer it came from, the raw team/member layers, and whether
42
+ * this App may write to the team layer.
43
+ */
44
+ export type ResolvedAppStorage = typeof resolvedAppStorageSchema.Type;
45
+ /**
46
+ * Validates a write request: the key, scope, value to store, and the
47
+ * revision it's conditioned on (`null` to write unconditionally).
48
+ */
49
+ export declare const appStorageWriteSchema: Schema.Struct<{
50
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
51
+ readonly key: Schema.String;
52
+ readonly scope: Schema.Literals<readonly ["team", "member"]>;
53
+ readonly basedOn: Schema.NullOr<Schema.Int>;
54
+ }>;
55
+ /**
56
+ * Validates a reset request: the key, scope, and the revision it's
57
+ * conditioned on (`null` to reset unconditionally).
58
+ */
59
+ export declare const appStorageResetSchema: Schema.Struct<{
60
+ key: Schema.String;
61
+ scope: Schema.Literals<readonly ["team", "member"]>;
62
+ basedOn: Schema.NullOr<Schema.Int>;
63
+ }>;
64
+ /** A validated write request for one storage key. */
65
+ export type AppStorageWrite = typeof appStorageWriteSchema.Type;
66
+ /** A validated reset request for one storage key. */
67
+ export type AppStorageReset = typeof appStorageResetSchema.Type;
68
+ /** Validates a bare revision number returned after a write or reset. */
69
+ export declare const appStorageRevisionSchema: Schema.Struct<{
70
+ readonly revision: Schema.Int;
71
+ }>;
72
+ /**
73
+ * Validates a change-event payload pushed when a storage key's value
74
+ * changes, naming the App, key, scope, and resulting revision.
75
+ */
76
+ export declare const appStorageEventSchema: Schema.Struct<{
77
+ readonly appId: Schema.String;
78
+ readonly key: Schema.String;
79
+ readonly scope: Schema.Literals<readonly ["team", "member"]>;
80
+ readonly revision: Schema.Int;
81
+ }>;
82
+ /**
83
+ * A change-event payload identifying which App, key, scope, and
84
+ * resulting revision changed.
85
+ */
86
+ export type AppStorageEvent = typeof appStorageEventSchema.Type;
87
+ /**
88
+ * The wire-level outcome of a storage operation: either an accepted
89
+ * value or a rejection carrying an {@link AppStorageError} code.
90
+ */
91
+ export type AppStorageResult<A> = Readonly<{
92
+ kind: "accepted";
93
+ value: A;
94
+ }> | Readonly<{
95
+ kind: "rejected";
96
+ code: AppStorageError["code"];
97
+ }>;
98
+ /**
99
+ * Validates the wire result of a read: either an accepted resolved
100
+ * value or a rejection code.
101
+ */
102
+ export declare const appStorageReadResultSchema: Schema.Union<readonly [Schema.Struct<{
103
+ readonly kind: Schema.Literal<"accepted">;
104
+ readonly value: Schema.Struct<{
105
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
106
+ readonly source: Schema.Literals<readonly ["member", "team", "none"]>;
107
+ readonly team: Schema.NullOr<Schema.Struct<{
108
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
109
+ readonly revision: Schema.Int;
110
+ }>>;
111
+ readonly member: Schema.NullOr<Schema.Struct<{
112
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
113
+ readonly revision: Schema.Int;
114
+ }>>;
115
+ readonly canWriteTeam: Schema.Boolean;
116
+ }>;
117
+ }>, Schema.Struct<{
118
+ readonly kind: Schema.Literal<"rejected">;
119
+ readonly code: Schema.Literals<readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"]>;
120
+ }>]>;
121
+ /**
122
+ * Validates the wire result of a write or reset: either an accepted
123
+ * revision or a rejection code.
124
+ */
125
+ export declare const appStorageMutationResultSchema: Schema.Union<readonly [Schema.Struct<{
126
+ readonly kind: Schema.Literal<"accepted">;
127
+ readonly value: Schema.Struct<{
128
+ readonly revision: Schema.Int;
129
+ }>;
130
+ }>, Schema.Struct<{
131
+ readonly kind: Schema.Literal<"rejected">;
132
+ readonly code: Schema.Literals<readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"]>;
133
+ }>]>;
134
+ /** The read result at a host broker, retaining its existing admission/failure reply. */
135
+ export declare const appStorageBrokerReadResultSchema: Schema.Union<readonly [Schema.Union<readonly [Schema.Struct<{
136
+ readonly kind: Schema.Literal<"accepted">;
137
+ readonly value: Schema.Struct<{
138
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
139
+ readonly source: Schema.Literals<readonly ["member", "team", "none"]>;
140
+ readonly team: Schema.NullOr<Schema.Struct<{
141
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
142
+ readonly revision: Schema.Int;
143
+ }>>;
144
+ readonly member: Schema.NullOr<Schema.Struct<{
145
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
146
+ readonly revision: Schema.Int;
147
+ }>>;
148
+ readonly canWriteTeam: Schema.Boolean;
149
+ }>;
150
+ }>, Schema.Struct<{
151
+ readonly kind: Schema.Literal<"rejected">;
152
+ readonly code: Schema.Literals<readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"]>;
153
+ }>]>, Schema.Struct<{
154
+ readonly error: Schema.String;
155
+ }>]>;
156
+ /** The shared write/reset result at a host broker, including its existing failure reply. */
157
+ export declare const appStorageBrokerMutationResultSchema: Schema.Union<readonly [Schema.Union<readonly [Schema.Struct<{
158
+ readonly kind: Schema.Literal<"accepted">;
159
+ readonly value: Schema.Struct<{
160
+ readonly revision: Schema.Int;
161
+ }>;
162
+ }>, Schema.Struct<{
163
+ readonly kind: Schema.Literal<"rejected">;
164
+ readonly code: Schema.Literals<readonly ["invalid", "undeclared_key", "scope_not_declared", "owner_required", "too_large", "quota_exceeded", "conflict", "unavailable"]>;
165
+ }>]>, Schema.Struct<{
166
+ readonly error: Schema.String;
167
+ }>]>;
@@ -0,0 +1,115 @@
1
+ import * as Schema from "effect/Schema";
2
+ import { appStorageScopes, appStorageKeyNameSchema, } from "@fungi.computer/puffball/app";
3
+ export { appStorageKeyNameSchema };
4
+ /**
5
+ * Storage error codes the host and client agree on: invalid input, an
6
+ * undeclared key, a scope this App never declared, a member-only action
7
+ * tried without a member, a value or quota that is too large, a write
8
+ * conflict, or a transient host failure.
9
+ */
10
+ export const appStorageErrorCodes = [
11
+ "invalid",
12
+ "undeclared_key",
13
+ "scope_not_declared",
14
+ "owner_required",
15
+ "too_large",
16
+ "quota_exceeded",
17
+ "conflict",
18
+ "unavailable",
19
+ ];
20
+ /** Validates that a value is one of the known storage error codes. */
21
+ export const appStorageErrorCodeSchema = Schema.Literals(appStorageErrorCodes);
22
+ /**
23
+ * Thrown by the storage client when a read, write, reset, or watch is
24
+ * rejected by the host; `code` identifies why.
25
+ */
26
+ export class AppStorageError extends Error {
27
+ code;
28
+ constructor(code, options) {
29
+ super(code, options);
30
+ this.code = code;
31
+ }
32
+ }
33
+ const revision = Schema.Int.check(Schema.isGreaterThan(0));
34
+ const layer = Schema.Struct({ value: Schema.Json, revision });
35
+ /**
36
+ * Validates the resolved shape of a storage key: its merged value, which
37
+ * layer it came from, the raw team and member layers it was merged from,
38
+ * and whether this App may write to the team layer.
39
+ */
40
+ export const resolvedAppStorageSchema = Schema.Struct({
41
+ value: Schema.Json,
42
+ source: Schema.Literals(["member", "team", "none"]),
43
+ team: Schema.NullOr(layer),
44
+ member: Schema.NullOr(layer),
45
+ canWriteTeam: Schema.Boolean,
46
+ });
47
+ const mutation = {
48
+ key: appStorageKeyNameSchema,
49
+ scope: Schema.Literals(appStorageScopes),
50
+ basedOn: Schema.NullOr(revision),
51
+ };
52
+ /**
53
+ * Validates a write request: the key, scope, value to store, and the
54
+ * revision it's conditioned on (`null` to write unconditionally).
55
+ */
56
+ export const appStorageWriteSchema = Schema.Struct({
57
+ ...mutation,
58
+ value: Schema.Json,
59
+ });
60
+ /**
61
+ * Validates a reset request: the key, scope, and the revision it's
62
+ * conditioned on (`null` to reset unconditionally).
63
+ */
64
+ export const appStorageResetSchema = Schema.Struct(mutation);
65
+ /** Validates a bare revision number returned after a write or reset. */
66
+ export const appStorageRevisionSchema = Schema.Struct({ revision });
67
+ /**
68
+ * Validates a change-event payload pushed when a storage key's value
69
+ * changes, naming the App, key, scope, and resulting revision.
70
+ */
71
+ export const appStorageEventSchema = Schema.Struct({
72
+ appId: Schema.String,
73
+ key: appStorageKeyNameSchema,
74
+ scope: Schema.Literals(appStorageScopes),
75
+ revision,
76
+ });
77
+ /**
78
+ * Validates the wire result of a read: either an accepted resolved
79
+ * value or a rejection code.
80
+ */
81
+ export const appStorageReadResultSchema = Schema.Union([
82
+ Schema.Struct({
83
+ kind: Schema.Literal("accepted"),
84
+ value: resolvedAppStorageSchema,
85
+ }),
86
+ Schema.Struct({
87
+ kind: Schema.Literal("rejected"),
88
+ code: appStorageErrorCodeSchema,
89
+ }),
90
+ ]);
91
+ /**
92
+ * Validates the wire result of a write or reset: either an accepted
93
+ * revision or a rejection code.
94
+ */
95
+ export const appStorageMutationResultSchema = Schema.Union([
96
+ Schema.Struct({
97
+ kind: Schema.Literal("accepted"),
98
+ value: appStorageRevisionSchema,
99
+ }),
100
+ Schema.Struct({
101
+ kind: Schema.Literal("rejected"),
102
+ code: appStorageErrorCodeSchema,
103
+ }),
104
+ ]);
105
+ const brokerRefusal = Schema.Struct({ error: Schema.String });
106
+ /** The read result at a host broker, retaining its existing admission/failure reply. */
107
+ export const appStorageBrokerReadResultSchema = Schema.Union([
108
+ appStorageReadResultSchema,
109
+ brokerRefusal,
110
+ ]);
111
+ /** The shared write/reset result at a host broker, including its existing failure reply. */
112
+ export const appStorageBrokerMutationResultSchema = Schema.Union([
113
+ appStorageMutationResultSchema,
114
+ brokerRefusal,
115
+ ]);
@@ -0,0 +1,72 @@
1
+ import { type CapabilityContract } from "./capabilities.js";
2
+ import type { ReadonlyStore } from "./store.js";
3
+ import { type AppStorageResult, type AppStorageWrite, type AppStorageReset, type ResolvedAppStorage } from "./storage-wire.js";
4
+ export * from "./storage-wire.js";
5
+ /**
6
+ * A live subscription to one storage key's resolved value: read the
7
+ * current value, subscribe to changes, and close when done watching.
8
+ */
9
+ export type AppStorageWatch = ReadonlyStore<ResolvedAppStorage> & Disposable & {
10
+ /** Stop watching and release the underlying event subscription. */
11
+ close(): void;
12
+ };
13
+ /** This App's storage client, scoped to its declared member/team data. */
14
+ export type AppStorage = Readonly<{
15
+ /** Read the resolved value for `key`, merging team and member layers. */
16
+ read(key: string): Promise<ResolvedAppStorage>;
17
+ /**
18
+ * Write a value for a key and scope, optionally conditioned on
19
+ * `basedOn` revision; resolves with the resulting revision.
20
+ */
21
+ write(input: AppStorageWrite): Promise<{
22
+ revision: number;
23
+ }>;
24
+ /**
25
+ * Clear a key's value for a scope, optionally conditioned on
26
+ * `basedOn` revision; resolves with the resulting revision.
27
+ */
28
+ reset(input: AppStorageReset): Promise<{
29
+ revision: number;
30
+ }>;
31
+ /** Resolves after the first admitted snapshot; close when the consumer leaves. */
32
+ watch(key: string): Promise<AppStorageWatch>;
33
+ }>;
34
+ /**
35
+ * A live object capability backing one key's change-event stream,
36
+ * adapted to Fetch so it can drive an `EventSource`.
37
+ */
38
+ export type AppStorageEventHandle = Disposable & {
39
+ /** Forward one `EventSource` request to the host's event stream. */
40
+ fetch(request: Request): Promise<Response>;
41
+ /** Release the change-event stream's underlying object capability. */
42
+ close(): Promise<void>;
43
+ };
44
+ /**
45
+ * The raw wire contract this capability negotiates with the host,
46
+ * before client-side input validation and error unwrapping.
47
+ */
48
+ export type AppStorageWire = {
49
+ /**
50
+ * Read a key's resolved value over the wire; resolves with an
51
+ * accepted value or a rejection code.
52
+ */
53
+ read(key: string): Promise<AppStorageResult<ResolvedAppStorage>>;
54
+ /**
55
+ * Write a key's value over the wire; resolves with the accepted
56
+ * revision or a rejection code.
57
+ */
58
+ write(input: AppStorageWrite): Promise<AppStorageResult<{
59
+ revision: number;
60
+ }>>;
61
+ /**
62
+ * Reset a key's value over the wire; resolves with the accepted
63
+ * revision or a rejection code.
64
+ */
65
+ reset(input: AppStorageReset): Promise<AppStorageResult<{
66
+ revision: number;
67
+ }>>;
68
+ /** Open the change-event stream for a key, as a Fetch-adapted handle. */
69
+ openEvents(key: string): Promise<AppStorageEventHandle>;
70
+ };
71
+ /** This App's own declared data. The host seals App and member identities. */
72
+ export declare const appStorage: CapabilityContract<AppStorage>;
@@ -0,0 +1,143 @@
1
+ import * as Schema from "effect/Schema";
2
+ import * as z from "zod";
3
+ import { EventSource } from "eventsource";
4
+ import { defineCapability } from "./capabilities.js";
5
+ import { rpcHandleSchema, rpcDataSchema, rpcMethod, rpcFetchHandleSchema, } from "./internal/rpc-contract.js";
6
+ import { createReadonlyStore } from "./internal/store.js";
7
+ import { reportCatchFailure } from "./failure.js";
8
+ import { AppStorageError, appStorageKeyNameSchema, appStorageWriteSchema, appStorageResetSchema, appStorageReadResultSchema, appStorageMutationResultSchema, appStorageEventSchema, } from "./storage-wire.js";
9
+ export * from "./storage-wire.js";
10
+ const data = (schema) => rpcDataSchema(z
11
+ .unknown()
12
+ .transform((value) => Schema.decodeUnknownSync(schema, { onExcessProperty: "error" })(value)));
13
+ const rawSchema = rpcHandleSchema({
14
+ read: rpcMethod(data(appStorageReadResultSchema)),
15
+ write: rpcMethod(data(appStorageMutationResultSchema)),
16
+ reset: rpcMethod(data(appStorageMutationResultSchema)),
17
+ openEvents: rpcMethod(rpcFetchHandleSchema),
18
+ });
19
+ const unwrap = (result) => {
20
+ if (result.kind === "rejected")
21
+ throw new AppStorageError(result.code);
22
+ return result.value;
23
+ };
24
+ const parseInput = (schema, value) => {
25
+ const parsed = Schema.decodeUnknownResult(schema, {
26
+ onExcessProperty: "error",
27
+ })(value);
28
+ if (parsed._tag === "Failure")
29
+ throw new AppStorageError("invalid", { cause: parsed.failure });
30
+ return parsed.success;
31
+ };
32
+ const parseKey = (key) => parseInput(appStorageKeyNameSchema, key);
33
+ function client(raw) {
34
+ const read = async (key) => unwrap(await raw.read(parseKey(key)));
35
+ return {
36
+ read,
37
+ write: async (input) => unwrap(await raw.write(parseInput(appStorageWriteSchema, input))),
38
+ reset: async (input) => unwrap(await raw.reset(parseInput(appStorageResetSchema, input))),
39
+ async watch(input) {
40
+ const key = parseKey(input);
41
+ const handle = await raw.openEvents(key);
42
+ let closed = false;
43
+ const isClosed = () => closed;
44
+ let loading;
45
+ let dirty = false;
46
+ const shouldRead = () => dirty && !isClosed();
47
+ let store;
48
+ let resolveInitial = () => undefined;
49
+ let rejectInitial = () => undefined;
50
+ const initial = new Promise((resolve, reject) => {
51
+ resolveInitial = resolve;
52
+ rejectInitial = reject;
53
+ });
54
+ const events = new EventSource("https://app-storage.fungi.invalid/events", {
55
+ fetch: async (url, init) => {
56
+ const response = await handle.fetch(new Request(url, init));
57
+ if (!response.ok) {
58
+ const parsed = Schema.decodeUnknownResult(appStorageReadResultSchema)(await response.json());
59
+ const failure = new AppStorageError(parsed._tag === "Success" && parsed.success.kind === "rejected"
60
+ ? parsed.success.code
61
+ : "unavailable");
62
+ fail(failure);
63
+ throw failure;
64
+ }
65
+ return response;
66
+ },
67
+ });
68
+ const close = () => {
69
+ if (closed)
70
+ return;
71
+ closed = true;
72
+ events.close();
73
+ rejectInitial(new AppStorageError("unavailable"));
74
+ void handle
75
+ .close()
76
+ .catch((cause) => {
77
+ reportCatchFailure("storage.watch.close", cause);
78
+ })
79
+ .finally(() => {
80
+ handle[Symbol.dispose]();
81
+ });
82
+ };
83
+ const fail = (cause) => {
84
+ rejectInitial(cause instanceof AppStorageError
85
+ ? cause
86
+ : new AppStorageError("unavailable", { cause }));
87
+ if (!closed && store !== undefined)
88
+ reportCatchFailure("storage.watch", cause);
89
+ close();
90
+ };
91
+ const refresh = () => {
92
+ dirty = true;
93
+ if (loading !== undefined || closed)
94
+ return;
95
+ loading = (async () => {
96
+ while (shouldRead()) {
97
+ dirty = false;
98
+ const next = await read(key);
99
+ if (isClosed())
100
+ return;
101
+ if (store === undefined) {
102
+ const first = createReadonlyStore(next);
103
+ store = first;
104
+ resolveInitial({
105
+ get: () => first.get(),
106
+ subscribe: (listener) => first.subscribe(listener),
107
+ close,
108
+ [Symbol.dispose]: close,
109
+ });
110
+ }
111
+ else
112
+ store.update(next);
113
+ }
114
+ })()
115
+ .catch(fail)
116
+ .finally(() => {
117
+ loading = undefined;
118
+ if (dirty && !closed)
119
+ refresh();
120
+ });
121
+ };
122
+ // The owner emits ready only after registering the subscription. Reading
123
+ // then closes the initial-read/subscription race and every reconnect gap.
124
+ events.addEventListener("ready", refresh);
125
+ events.addEventListener("changed", (event) => {
126
+ const changed = Schema.decodeUnknownResult(Schema.fromJsonString(appStorageEventSchema), { onExcessProperty: "error" })(event.data);
127
+ if (changed._tag === "Failure")
128
+ fail(changed.failure);
129
+ else if (changed.success.key !== key)
130
+ fail(new AppStorageError("invalid"));
131
+ else
132
+ refresh();
133
+ });
134
+ events.onerror = (cause) => {
135
+ if (store === undefined || events.readyState === EventSource.CLOSED)
136
+ fail(cause);
137
+ };
138
+ return initial;
139
+ },
140
+ };
141
+ }
142
+ /** This App's own declared data. The host seals App and member identities. */
143
+ export const appStorage = defineCapability("app.storage", 1, rawSchema.transform(client));
@@ -0,0 +1,11 @@
1
+ /** Releases a subscription or other held resource. Call once; further
2
+ * calls are a no-op. */
3
+ export type Disposer = () => void;
4
+ /** A retained SDK-owned snapshot. */
5
+ export type ReadonlyStore<T> = {
6
+ /** The current value; always available, even before any subscription. */
7
+ get(): T;
8
+ /** Call `listener` on every change until the returned Disposer runs.
9
+ * Does not emit the current value immediately on subscribe. */
10
+ subscribe(listener: (value: T) => void): Disposer;
11
+ };
package/dist/store.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import type { GitCommit, GitRepositoryInfo } from "../git.js";
2
+ /** Real smart HTTP writes and git plumbing reads in one disposable bare repository. */
3
+ export declare function realGit(): {
4
+ git: Readonly<{
5
+ create(name: string, options?: {
6
+ description?: string;
7
+ defaultBranch?: string;
8
+ }): Promise<GitRepositoryInfo>;
9
+ fork(source: string, target: string, options?: {
10
+ description?: string;
11
+ }): Promise<GitRepositoryInfo>;
12
+ cloneUrl(name: string): Promise<string>;
13
+ info(name: string): Promise<GitRepositoryInfo | null>;
14
+ delete(name: string): Promise<boolean>;
15
+ log(name: string, options: {
16
+ ref: string;
17
+ limit?: number;
18
+ offset?: number;
19
+ }): Promise<GitCommit[]>;
20
+ readCommit(name: string, hash: string): Promise<GitCommit | null>;
21
+ readTree(name: string, hash: string): Promise<import("../git.js").GitTreeEntry[] | null>;
22
+ readBlob(name: string, hash: string): Promise<Uint8Array | null>;
23
+ refs(name: string): Promise<{
24
+ name: string;
25
+ hash: string;
26
+ }[]>;
27
+ exchange(name: string, request: import("../git.js").GitExchangeRequest): Promise<import("../git.js").GitExchangeResponse>;
28
+ }>;
29
+ run: (name: string, ...args: string[]) => string;
30
+ close: () => void;
31
+ };