@akterjs/conformance 0.0.0-stage → 0.1.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.
Files changed (57) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +52 -2
  3. package/dist/client-contract.suite.d.mts +23 -0
  4. package/dist/client-contract.suite.mjs +279 -0
  5. package/dist/client-target.errors.d.mts +8 -0
  6. package/dist/client-target.errors.mjs +4 -0
  7. package/dist/engine-conformance.suite.d.mts +19 -0
  8. package/dist/engine-conformance.suite.mjs +357 -0
  9. package/dist/fork/fork-conformance.suite.d.mts +20 -0
  10. package/dist/fork/fork-conformance.suite.mjs +167 -0
  11. package/dist/guarantee-titles.pure.d.mts +31 -0
  12. package/dist/guarantee-titles.pure.mjs +32 -0
  13. package/dist/ledger/ledger-calls.pure.d.mts +79 -0
  14. package/dist/ledger/ledger-calls.pure.mjs +111 -0
  15. package/dist/ledger/ledger-checks.pure.d.mts +21 -0
  16. package/dist/ledger/ledger-checks.pure.mjs +37 -0
  17. package/dist/ledger/ledger.actor.d.mts +13 -0
  18. package/dist/ledger/ledger.actor.mjs +115 -0
  19. package/dist/ledger/ledger.contract.d.mts +310 -0
  20. package/dist/ledger/ledger.contract.mjs +112 -0
  21. package/dist/ledger/plain-ledger.actor.d.mts +4 -0
  22. package/dist/ledger/plain-ledger.actor.mjs +214 -0
  23. package/dist/rejected.errors.d.mts +8 -0
  24. package/dist/rejected.errors.mjs +4 -0
  25. package/dist/tally-clients.layer.d.mts +39 -0
  26. package/dist/tally-clients.layer.mjs +97 -0
  27. package/dist/tally.actor.d.mts +49 -0
  28. package/dist/tally.actor.mjs +26 -0
  29. package/dist/tally.contract.d.mts +51 -0
  30. package/dist/tally.contract.mjs +28 -0
  31. package/dist/workbench/computer-conformance.suite.d.mts +15 -0
  32. package/dist/workbench/computer-conformance.suite.mjs +330 -0
  33. package/dist/workbench/workbench-calls.pure.d.mts +45 -0
  34. package/dist/workbench/workbench-calls.pure.mjs +75 -0
  35. package/dist/workbench/workbench.actor.d.mts +4 -0
  36. package/dist/workbench/workbench.actor.mjs +107 -0
  37. package/dist/workbench/workbench.contract.d.mts +220 -0
  38. package/dist/workbench/workbench.contract.mjs +54 -0
  39. package/package.json +86 -3
  40. package/src/client-contract.suite.ts +413 -0
  41. package/src/client-target.errors.ts +7 -0
  42. package/src/engine-conformance.suite.ts +484 -0
  43. package/src/fork/fork-conformance.suite.ts +204 -0
  44. package/src/guarantee-titles.pure.ts +50 -0
  45. package/src/ledger/ledger-calls.pure.ts +179 -0
  46. package/src/ledger/ledger-checks.pure.ts +84 -0
  47. package/src/ledger/ledger.actor.ts +196 -0
  48. package/src/ledger/ledger.contract.ts +76 -0
  49. package/src/ledger/plain-ledger.actor.ts +246 -0
  50. package/src/rejected.errors.ts +6 -0
  51. package/src/tally-clients.layer.ts +221 -0
  52. package/src/tally.actor.ts +28 -0
  53. package/src/tally.contract.ts +22 -0
  54. package/src/workbench/computer-conformance.suite.ts +380 -0
  55. package/src/workbench/workbench-calls.pure.ts +92 -0
  56. package/src/workbench/workbench.actor.ts +175 -0
  57. package/src/workbench/workbench.contract.ts +47 -0
@@ -0,0 +1,310 @@
1
+ import { Schema } from "effect";
2
+ declare const EntryId: Schema.brand<Schema.String, "EntryId">;
3
+ declare const Cents: Schema.brand<Schema.Int, "Cents">;
4
+ type Cents = typeof Cents.Type;
5
+ declare const Entry: Schema.Struct<{
6
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
7
+ readonly id: Schema.brand<Schema.String, "EntryId">;
8
+ }>;
9
+ type Entry = typeof Entry.Type;
10
+ type Account = typeof Account.Type;
11
+ declare const Account: Schema.Struct<{
12
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
13
+ readonly closed: Schema.Boolean;
14
+ }>;
15
+ declare const OverdrawnError_base: Schema.Class<OverdrawnError, Schema.TaggedStruct<"OverdrawnError", {
16
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
17
+ }>, import("effect/Cause").YieldableError & {
18
+ readonly brand: unique symbol;
19
+ }>;
20
+ declare class OverdrawnError extends OverdrawnError_base {}
21
+ /** The patch the later build's `release` declares: it releases twice the approved amount, for holds it started. */
22
+ declare const doubled = "double";
23
+ declare const Ledger: import("@akterjs/effect/contract").Actor<"Ledger", import("@akterjs/effect/contract").DefinitionOf<{
24
+ readonly callers: {
25
+ readonly actor: Schema.Struct<{
26
+ readonly actor: Schema.String;
27
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
28
+ readonly key: Schema.String;
29
+ }>;
30
+ readonly service: Schema.Struct<{
31
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
32
+ }>;
33
+ readonly user: Schema.Struct<{
34
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
35
+ }>;
36
+ };
37
+ readonly commands: {
38
+ readonly approve: import("@akterjs/effect/contract").Command<Schema.Struct<{
39
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
40
+ readonly job: Schema.String;
41
+ readonly refuse: Schema.Boolean;
42
+ }>, Schema.Void, Schema.Never, never>;
43
+ readonly close: import("@akterjs/effect/contract").Command<Schema.Void, Schema.Void, Schema.Never, "service">;
44
+ readonly crash: import("@akterjs/effect/contract").Command<Schema.Struct<{
45
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
46
+ }>, Schema.Void, Schema.Never, never>;
47
+ readonly credit: import("@akterjs/effect/contract").Command<Schema.Struct<{
48
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
49
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, "actor">;
50
+ readonly deposit: import("@akterjs/effect/contract").Command<Schema.Struct<{
51
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
52
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, never>;
53
+ readonly depositLater: import("@akterjs/effect/contract").Command<Schema.Struct<{
54
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
55
+ readonly minutes: Schema.Int;
56
+ }>, Schema.Void, Schema.Never, never>;
57
+ readonly hold: import("@akterjs/effect/contract").Command<Schema.Void, Schema.String, Schema.Never, never>;
58
+ readonly tamper: import("@akterjs/effect/contract").Command<Schema.Struct<{
59
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
60
+ }>, Schema.Void, Schema.Never, never>;
61
+ readonly transfer: import("@akterjs/effect/contract").Command<Schema.Struct<{
62
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
63
+ readonly to: Schema.brand<Schema.String, "AccountId">;
64
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
65
+ readonly withdraw: import("@akterjs/effect/contract").Command<Schema.Struct<{
66
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
67
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
68
+ };
69
+ readonly files: import("@akterjs/effect/contract").FileAccess<"user">;
70
+ readonly initial: () => {
71
+ balance: number & import("effect/Brand").Brand<"Cents">;
72
+ closed: boolean;
73
+ };
74
+ readonly key: Schema.brand<Schema.String, "AccountId">;
75
+ readonly queries: {
76
+ readonly account: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Struct<{
77
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
78
+ readonly closed: Schema.Boolean;
79
+ }>, Schema.Never, never>;
80
+ readonly entries: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.Struct<{
81
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
82
+ readonly id: Schema.brand<Schema.String, "EntryId">;
83
+ }>>, Schema.Never, never>;
84
+ readonly scribble: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Void, Schema.Never, never>;
85
+ readonly tables: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.String>, Schema.Never, never>;
86
+ };
87
+ readonly state: Schema.Struct<{
88
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
89
+ readonly closed: Schema.Boolean;
90
+ }>;
91
+ readonly jobs: {
92
+ release: import("@akterjs/effect/contract").Job<{}, Schema.brand<Schema.Int, "Cents">, Schema.Never, string>;
93
+ };
94
+ }>> & import("@akterjs/effect/contract").ActorHistory<import("@akterjs/effect/contract").DefinitionOf<{
95
+ readonly callers: {
96
+ readonly actor: Schema.Struct<{
97
+ readonly actor: Schema.String;
98
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
99
+ readonly key: Schema.String;
100
+ }>;
101
+ readonly service: Schema.Struct<{
102
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
103
+ }>;
104
+ readonly user: Schema.Struct<{
105
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
106
+ }>;
107
+ };
108
+ readonly commands: {
109
+ readonly approve: import("@akterjs/effect/contract").Command<Schema.Struct<{
110
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
111
+ readonly job: Schema.String;
112
+ readonly refuse: Schema.Boolean;
113
+ }>, Schema.Void, Schema.Never, never>;
114
+ readonly close: import("@akterjs/effect/contract").Command<Schema.Void, Schema.Void, Schema.Never, "service">;
115
+ readonly crash: import("@akterjs/effect/contract").Command<Schema.Struct<{
116
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
117
+ }>, Schema.Void, Schema.Never, never>;
118
+ readonly credit: import("@akterjs/effect/contract").Command<Schema.Struct<{
119
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
120
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, "actor">;
121
+ readonly deposit: import("@akterjs/effect/contract").Command<Schema.Struct<{
122
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
123
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, never>;
124
+ readonly depositLater: import("@akterjs/effect/contract").Command<Schema.Struct<{
125
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
126
+ readonly minutes: Schema.Int;
127
+ }>, Schema.Void, Schema.Never, never>;
128
+ readonly hold: import("@akterjs/effect/contract").Command<Schema.Void, Schema.String, Schema.Never, never>;
129
+ readonly tamper: import("@akterjs/effect/contract").Command<Schema.Struct<{
130
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
131
+ }>, Schema.Void, Schema.Never, never>;
132
+ readonly transfer: import("@akterjs/effect/contract").Command<Schema.Struct<{
133
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
134
+ readonly to: Schema.brand<Schema.String, "AccountId">;
135
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
136
+ readonly withdraw: import("@akterjs/effect/contract").Command<Schema.Struct<{
137
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
138
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
139
+ };
140
+ readonly files: import("@akterjs/effect/contract").FileAccess<"user">;
141
+ readonly initial: () => {
142
+ balance: number & import("effect/Brand").Brand<"Cents">;
143
+ closed: boolean;
144
+ };
145
+ readonly key: Schema.brand<Schema.String, "AccountId">;
146
+ readonly queries: {
147
+ readonly account: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Struct<{
148
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
149
+ readonly closed: Schema.Boolean;
150
+ }>, Schema.Never, never>;
151
+ readonly entries: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.Struct<{
152
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
153
+ readonly id: Schema.brand<Schema.String, "EntryId">;
154
+ }>>, Schema.Never, never>;
155
+ readonly scribble: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Void, Schema.Never, never>;
156
+ readonly tables: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.String>, Schema.Never, never>;
157
+ };
158
+ readonly state: Schema.Struct<{
159
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
160
+ readonly closed: Schema.Boolean;
161
+ }>;
162
+ readonly jobs: {
163
+ release: import("@akterjs/effect/contract").Job<{}, Schema.brand<Schema.Int, "Cents">, Schema.Never, string>;
164
+ };
165
+ }>>;
166
+ /** The Ledger deployed again with its `release` job patched, over holds the earlier build started. */
167
+ declare const PatchedLedger: import("@akterjs/effect/contract").Actor<"Ledger", import("@akterjs/effect/contract").DefinitionOf<{
168
+ readonly callers: {
169
+ readonly actor: Schema.Struct<{
170
+ readonly actor: Schema.String;
171
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
172
+ readonly key: Schema.String;
173
+ }>;
174
+ readonly service: Schema.Struct<{
175
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
176
+ }>;
177
+ readonly user: Schema.Struct<{
178
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
179
+ }>;
180
+ };
181
+ readonly commands: {
182
+ readonly approve: import("@akterjs/effect/contract").Command<Schema.Struct<{
183
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
184
+ readonly job: Schema.String;
185
+ readonly refuse: Schema.Boolean;
186
+ }>, Schema.Void, Schema.Never, never>;
187
+ readonly close: import("@akterjs/effect/contract").Command<Schema.Void, Schema.Void, Schema.Never, "service">;
188
+ readonly crash: import("@akterjs/effect/contract").Command<Schema.Struct<{
189
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
190
+ }>, Schema.Void, Schema.Never, never>;
191
+ readonly credit: import("@akterjs/effect/contract").Command<Schema.Struct<{
192
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
193
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, "actor">;
194
+ readonly deposit: import("@akterjs/effect/contract").Command<Schema.Struct<{
195
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
196
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, never>;
197
+ readonly depositLater: import("@akterjs/effect/contract").Command<Schema.Struct<{
198
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
199
+ readonly minutes: Schema.Int;
200
+ }>, Schema.Void, Schema.Never, never>;
201
+ readonly hold: import("@akterjs/effect/contract").Command<Schema.Void, Schema.String, Schema.Never, never>;
202
+ readonly tamper: import("@akterjs/effect/contract").Command<Schema.Struct<{
203
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
204
+ }>, Schema.Void, Schema.Never, never>;
205
+ readonly transfer: import("@akterjs/effect/contract").Command<Schema.Struct<{
206
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
207
+ readonly to: Schema.brand<Schema.String, "AccountId">;
208
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
209
+ readonly withdraw: import("@akterjs/effect/contract").Command<Schema.Struct<{
210
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
211
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
212
+ };
213
+ readonly files: import("@akterjs/effect/contract").FileAccess<"user">;
214
+ readonly initial: () => {
215
+ balance: number & import("effect/Brand").Brand<"Cents">;
216
+ closed: boolean;
217
+ };
218
+ readonly key: Schema.brand<Schema.String, "AccountId">;
219
+ readonly queries: {
220
+ readonly account: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Struct<{
221
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
222
+ readonly closed: Schema.Boolean;
223
+ }>, Schema.Never, never>;
224
+ readonly entries: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.Struct<{
225
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
226
+ readonly id: Schema.brand<Schema.String, "EntryId">;
227
+ }>>, Schema.Never, never>;
228
+ readonly scribble: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Void, Schema.Never, never>;
229
+ readonly tables: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.String>, Schema.Never, never>;
230
+ };
231
+ readonly state: Schema.Struct<{
232
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
233
+ readonly closed: Schema.Boolean;
234
+ }>;
235
+ readonly jobs: {
236
+ release: import("@akterjs/effect/contract").Job<{}, Schema.brand<Schema.Int, "Cents">, Schema.Never, string>;
237
+ };
238
+ }>> & import("@akterjs/effect/contract").ActorHistory<import("@akterjs/effect/contract").DefinitionOf<{
239
+ readonly callers: {
240
+ readonly actor: Schema.Struct<{
241
+ readonly actor: Schema.String;
242
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
243
+ readonly key: Schema.String;
244
+ }>;
245
+ readonly service: Schema.Struct<{
246
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
247
+ }>;
248
+ readonly user: Schema.Struct<{
249
+ readonly id: Schema.brand<Schema.String, "PrincipalId">;
250
+ }>;
251
+ };
252
+ readonly commands: {
253
+ readonly approve: import("@akterjs/effect/contract").Command<Schema.Struct<{
254
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
255
+ readonly job: Schema.String;
256
+ readonly refuse: Schema.Boolean;
257
+ }>, Schema.Void, Schema.Never, never>;
258
+ readonly close: import("@akterjs/effect/contract").Command<Schema.Void, Schema.Void, Schema.Never, "service">;
259
+ readonly crash: import("@akterjs/effect/contract").Command<Schema.Struct<{
260
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
261
+ }>, Schema.Void, Schema.Never, never>;
262
+ readonly credit: import("@akterjs/effect/contract").Command<Schema.Struct<{
263
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
264
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, "actor">;
265
+ readonly deposit: import("@akterjs/effect/contract").Command<Schema.Struct<{
266
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
267
+ }>, Schema.brand<Schema.String, "EntryId">, Schema.Never, never>;
268
+ readonly depositLater: import("@akterjs/effect/contract").Command<Schema.Struct<{
269
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
270
+ readonly minutes: Schema.Int;
271
+ }>, Schema.Void, Schema.Never, never>;
272
+ readonly hold: import("@akterjs/effect/contract").Command<Schema.Void, Schema.String, Schema.Never, never>;
273
+ readonly tamper: import("@akterjs/effect/contract").Command<Schema.Struct<{
274
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
275
+ }>, Schema.Void, Schema.Never, never>;
276
+ readonly transfer: import("@akterjs/effect/contract").Command<Schema.Struct<{
277
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
278
+ readonly to: Schema.brand<Schema.String, "AccountId">;
279
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
280
+ readonly withdraw: import("@akterjs/effect/contract").Command<Schema.Struct<{
281
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
282
+ }>, Schema.brand<Schema.String, "EntryId">, typeof OverdrawnError, never>;
283
+ };
284
+ readonly files: import("@akterjs/effect/contract").FileAccess<"user">;
285
+ readonly initial: () => {
286
+ balance: number & import("effect/Brand").Brand<"Cents">;
287
+ closed: boolean;
288
+ };
289
+ readonly key: Schema.brand<Schema.String, "AccountId">;
290
+ readonly queries: {
291
+ readonly account: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Struct<{
292
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
293
+ readonly closed: Schema.Boolean;
294
+ }>, Schema.Never, never>;
295
+ readonly entries: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.Struct<{
296
+ readonly amount: Schema.brand<Schema.Int, "Cents">;
297
+ readonly id: Schema.brand<Schema.String, "EntryId">;
298
+ }>>, Schema.Never, never>;
299
+ readonly scribble: import("@akterjs/effect/contract").Query<Schema.Void, Schema.Void, Schema.Never, never>;
300
+ readonly tables: import("@akterjs/effect/contract").Query<Schema.Void, Schema.$Array<Schema.String>, Schema.Never, never>;
301
+ };
302
+ readonly state: Schema.Struct<{
303
+ readonly balance: Schema.brand<Schema.Int, "Cents">;
304
+ readonly closed: Schema.Boolean;
305
+ }>;
306
+ readonly jobs: {
307
+ release: import("@akterjs/effect/contract").Job<{}, Schema.brand<Schema.Int, "Cents">, Schema.Never, string>;
308
+ };
309
+ }>>;
310
+ export { Account, Cents, Entry, EntryId, Ledger, OverdrawnError, PatchedLedger, doubled };
@@ -0,0 +1,112 @@
1
+ import { Schema } from "effect";
2
+ import { Akter } from "@akterjs/effect/contract";
3
+ // src/ledger/ledger.contract.ts
4
+ const AccountId = Schema.String.pipe(Schema.brand("AccountId"));
5
+ const EntryId = Schema.String.pipe(Schema.brand("EntryId"));
6
+ const Cents = Schema.Int.pipe(Schema.brand("Cents"));
7
+ const openingCents = 0;
8
+ const Entry = Schema.Struct({
9
+ amount: Cents,
10
+ id: EntryId
11
+ });
12
+ const Account = Schema.Struct({
13
+ balance: Cents,
14
+ closed: Schema.Boolean
15
+ });
16
+ const Service = Schema.Struct({ id: Akter.PrincipalId });
17
+ var OverdrawnError = class extends Schema.TaggedError()("OverdrawnError", { balance: Cents }) {};
18
+ /** Everything the Ledger declares but its `release` job, which the two builds below declare with different patches. */
19
+ const ledgerOptions = {
20
+ callers: {
21
+ actor: Akter.ActorPrincipal,
22
+ service: Service,
23
+ user: Akter.Principal
24
+ },
25
+ commands: {
26
+ approve: Akter.command({
27
+ payload: {
28
+ amount: Cents,
29
+ job: Schema.String,
30
+ refuse: Schema.Boolean
31
+ },
32
+ success: Schema.Void
33
+ }),
34
+ close: Akter.command({
35
+ callers: ["service"],
36
+ success: Schema.Void
37
+ }),
38
+ crash: Akter.command({
39
+ payload: { amount: Cents },
40
+ success: Schema.Void
41
+ }),
42
+ credit: Akter.command({
43
+ callers: ["actor"],
44
+ payload: { amount: Cents },
45
+ success: EntryId
46
+ }),
47
+ deposit: Akter.command({
48
+ payload: { amount: Cents },
49
+ success: EntryId
50
+ }),
51
+ depositLater: Akter.command({
52
+ payload: {
53
+ amount: Cents,
54
+ minutes: Schema.Int
55
+ },
56
+ success: Schema.Void
57
+ }),
58
+ hold: Akter.command({ success: Schema.String }),
59
+ tamper: Akter.command({
60
+ payload: { amount: Cents },
61
+ success: Schema.Void
62
+ }),
63
+ transfer: Akter.command({
64
+ error: OverdrawnError,
65
+ payload: {
66
+ amount: Cents,
67
+ to: AccountId
68
+ },
69
+ success: EntryId
70
+ }),
71
+ withdraw: Akter.command({
72
+ error: OverdrawnError,
73
+ payload: { amount: Cents },
74
+ success: EntryId
75
+ })
76
+ },
77
+ files: Akter.fileAccess({ callers: ["user"] }),
78
+ initial: () => ({
79
+ balance: Cents.make(openingCents),
80
+ closed: false
81
+ }),
82
+ key: AccountId,
83
+ queries: {
84
+ account: Akter.query({ success: Account }),
85
+ entries: Akter.query({ success: Schema.Array(Entry) }),
86
+ scribble: Akter.query({ success: Schema.Void }),
87
+ tables: Akter.query({ success: Schema.Array(Schema.String) })
88
+ },
89
+ state: Account
90
+ };
91
+ /** The patch the later build's `release` declares: it releases twice the approved amount, for holds it started. */
92
+ const doubled = "double";
93
+ const noPatches = [];
94
+ const doubling = [doubled];
95
+ const Ledger = Akter.make("Ledger", {
96
+ ...ledgerOptions,
97
+ jobs: { release: Akter.job({
98
+ patches: noPatches,
99
+ payload: {},
100
+ success: Cents
101
+ }) }
102
+ });
103
+ /** The Ledger deployed again with its `release` job patched, over holds the earlier build started. */
104
+ const PatchedLedger = Akter.make("Ledger", {
105
+ ...ledgerOptions,
106
+ jobs: { release: Akter.job({
107
+ patches: doubling,
108
+ payload: {},
109
+ success: Cents
110
+ }) }
111
+ });
112
+ export { Account, Cents, Entry, EntryId, Ledger, OverdrawnError, PatchedLedger, doubled };
@@ -0,0 +1,4 @@
1
+ import { Ledgers } from "./ledger.actor.mjs";
2
+ /** The plain SDK's Ledgers, for `conformanceOf({ engine, ledgers: plainLedgers, skip })`: every engine must pass the suite on both SDKs. */
3
+ declare const plainLedgers: Ledgers;
4
+ export { plainLedgers };
@@ -0,0 +1,214 @@
1
+ import "./ledger-calls.pure.mjs";
2
+ import { doubled } from "./ledger.contract.mjs";
3
+ import { Array, Effect, Layer } from "effect";
4
+ import { Akter } from "@akterjs/effect";
5
+ import { Akter as Akter$1 } from "@akterjs/sdk";
6
+ import { engineOf } from "@akterjs/sdk/engine";
7
+ import { z } from "zod";
8
+ // src/ledger/plain-ledger.actor.ts
9
+ /** The plain SDK's Ledger: the wire contract of the Effect Ledger in `ledger.contract.ts`, so one suite checks both SDKs. */
10
+ const Cents = z.number().int();
11
+ const Amount = z.object({ amount: Cents });
12
+ const Later = z.object({
13
+ amount: Cents,
14
+ minutes: z.number().int()
15
+ });
16
+ const Approving = z.object({
17
+ amount: Cents,
18
+ job: z.string(),
19
+ refuse: z.boolean()
20
+ });
21
+ const Release = z.object({});
22
+ const Transfer = z.object({
23
+ amount: Cents,
24
+ to: z.string()
25
+ });
26
+ const EntryId = z.string();
27
+ const OverdrawnError = Akter$1.error("OverdrawnError", z.object({ balance: Cents }));
28
+ const Account = z.object({
29
+ balance: Cents,
30
+ closed: z.boolean()
31
+ });
32
+ const Entries = z.array(z.object({
33
+ amount: Cents,
34
+ id: EntryId
35
+ }));
36
+ const TableNames = z.array(z.object({ name: z.string() }));
37
+ const TableList = z.array(z.string()).readonly();
38
+ /** Everything the plain Ledger declares but its `release` job, which the two builds below declare with different patches. */
39
+ const ledgerOptions = {
40
+ callers: {
41
+ actor: Akter$1.ActorPrincipal,
42
+ service: z.object({ id: z.string() }),
43
+ user: Akter$1.Principal
44
+ },
45
+ commands: {
46
+ approve: Akter$1.command({ payload: Approving }),
47
+ close: Akter$1.command({ callers: ["service"] }),
48
+ crash: Akter$1.command({ payload: Amount }),
49
+ credit: Akter$1.command({
50
+ callers: ["actor"],
51
+ payload: Amount,
52
+ success: EntryId
53
+ }),
54
+ deposit: Akter$1.command({
55
+ payload: Amount,
56
+ success: EntryId
57
+ }),
58
+ depositLater: Akter$1.command({ payload: Later }),
59
+ hold: Akter$1.command({ success: z.string() }),
60
+ tamper: Akter$1.command({ payload: Amount }),
61
+ transfer: Akter$1.command({
62
+ errors: [OverdrawnError],
63
+ payload: Transfer,
64
+ success: EntryId
65
+ }),
66
+ withdraw: Akter$1.command({
67
+ errors: [OverdrawnError],
68
+ payload: Amount,
69
+ success: EntryId
70
+ })
71
+ },
72
+ files: Akter$1.fileAccess({ callers: ["user"] }),
73
+ initial: () => ({
74
+ balance: 0,
75
+ closed: false
76
+ }),
77
+ key: z.string(),
78
+ queries: {
79
+ account: Akter$1.query({ success: Account }),
80
+ entries: Akter$1.query({ success: Entries }),
81
+ scribble: Akter$1.query(),
82
+ tables: Akter$1.query({ success: TableList })
83
+ },
84
+ state: Account
85
+ };
86
+ const noPatches = [];
87
+ const doubling = [doubled];
88
+ const Ledger = Akter$1.make("Ledger", {
89
+ ...ledgerOptions,
90
+ jobs: { release: Akter$1.job({
91
+ patches: noPatches,
92
+ payload: Release,
93
+ success: Cents
94
+ }) }
95
+ });
96
+ /** The Ledger deployed again with its `release` job patched, over holds the earlier build started. */
97
+ const PatchedLedger = Akter$1.make("Ledger", {
98
+ ...ledgerOptions,
99
+ jobs: { release: Akter$1.job({
100
+ patches: doubling,
101
+ payload: Release,
102
+ success: Cents
103
+ }) }
104
+ });
105
+ const lowestBalance = 0;
106
+ const millisPerMinute = 6e4;
107
+ const scribbled = 1;
108
+ const insert = (sql, id, amount) => sql`INSERT INTO entries (id, amount) VALUES (${id}, ${amount})`;
109
+ /** Records an entry and moves the balance, as the Effect Ledger's `record` does. */
110
+ const record = (ctx, balance, amount) => {
111
+ const id = ctx.id();
112
+ insert(ctx.sql, id, amount);
113
+ ctx.update({ balance });
114
+ return id;
115
+ };
116
+ const withdrawal = (ctx, amount) => {
117
+ const balance = ctx.state.balance - amount;
118
+ const id = record(ctx, balance, amount);
119
+ if (balance < lowestBalance) throw new OverdrawnError({ balance });
120
+ return id;
121
+ };
122
+ /** Reads the engine's journal, then writes the engine's state table, which no handler may do. */
123
+ const tamperWith = (sql) => Array.appendAll(sql`SELECT count(*) AS commands FROM akter_commands`, sql`UPDATE akter_state SET value = value`);
124
+ const tableNames = (sql) => Array.map(TableNames.parse(sql`SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'akter_%' AND name NOT LIKE 'sqlite_%' ORDER BY name`), (row) => row.name);
125
+ /** Signals the held job, then throws after the signal when `refuse` is set, so the command rolls back with it. */
126
+ const approve = (ctx, { amount, job, refuse }) => {
127
+ ctx.signal(job, "approval", amount);
128
+ if (refuse) throw new Error("the approval was refused after signalling");
129
+ };
130
+ /** Waits for the approved amount and returns it, so its result records the entry. */
131
+ const release = (_payload, steps) => Effect.runPromise(Effect.map(Effect.promise(() => steps.waitFor("approval")), (value) => Cents.parse(value)));
132
+ const twice = 2;
133
+ /** The later build's release: twice the approved amount, but only for a hold this build started. */
134
+ const doublingRelease = (payload, steps) => Effect.runPromise(Effect.map(Effect.promise(() => release(payload, steps)), (amount) => {
135
+ if (steps.patched("double")) return amount * twice;
136
+ return amount;
137
+ }));
138
+ const released = (ctx, result) => {
139
+ if (result.outcome === "success") record(ctx, ctx.state.balance + result.value, result.value);
140
+ };
141
+ /** The build the suite opens first: the Ledger without patches. */
142
+ const firstBuild = {
143
+ job: release,
144
+ ledger: Ledger
145
+ };
146
+ const plainLedgerLayer = (migrations, { job, ledger } = firstBuild) => {
147
+ const implemented = ledger.implement({
148
+ commands: {
149
+ approve,
150
+ close: (ctx) => {
151
+ ctx.update({ closed: true });
152
+ },
153
+ crash: (ctx, { amount }) => {
154
+ record(ctx, ctx.state.balance + amount, amount);
155
+ throw new Error("the handler crashed after writing");
156
+ },
157
+ credit: (ctx, { amount }) => record(ctx, ctx.state.balance + amount, amount),
158
+ deposit: (ctx, { amount }) => record(ctx, ctx.state.balance + amount, amount),
159
+ depositLater: (ctx, { amount, minutes }) => {
160
+ ctx.schedule(minutes * millisPerMinute, Ledger.commands.deposit, { amount });
161
+ },
162
+ hold: (ctx) => ctx.start(ledger.jobs.release, {}),
163
+ tamper: (ctx, { amount }) => {
164
+ record(ctx, ctx.state.balance + amount, amount);
165
+ tamperWith(ctx.sql);
166
+ },
167
+ transfer: (ctx, { amount, to }) => {
168
+ ctx.send(Ledger.commands.credit, to, { amount });
169
+ return withdrawal(ctx, amount);
170
+ },
171
+ withdraw: (ctx, { amount }) => withdrawal(ctx, amount)
172
+ },
173
+ files: { authorize: (ctx, { access }) => access === "read" || ctx.principal.id === "ada" && !ctx.state.closed },
174
+ jobs: { release: job },
175
+ migrations,
176
+ queries: {
177
+ account: (ctx) => ({
178
+ balance: ctx.state.balance,
179
+ closed: ctx.state.closed
180
+ }),
181
+ entries: (ctx) => Entries.parse(ctx.sql`SELECT id, amount FROM entries ORDER BY rowid`),
182
+ scribble: (ctx) => {
183
+ insert(ctx.sql, "query", scribbled);
184
+ },
185
+ tables: (ctx) => tableNames(ctx.sql)
186
+ },
187
+ results: { release: released }
188
+ });
189
+ return engineOf(Akter$1.app([implemented])).layer.pipe(Layer.provide(Akter.jobs));
190
+ };
191
+ const createEntries = "CREATE TABLE entries (id TEXT PRIMARY KEY, amount INTEGER NOT NULL)";
192
+ const createNotes = "CREATE TABLE notes (id TEXT PRIMARY KEY, text TEXT NOT NULL)";
193
+ const entriesVersion = 1;
194
+ const notesVersion = 2;
195
+ const reservedVersion = 3;
196
+ const plainLedgerIntruding = (prefix) => plainLedgerLayer({
197
+ [entriesVersion]: createEntries,
198
+ [notesVersion]: createNotes,
199
+ [reservedVersion]: `CREATE TABLE "${prefix}intruder" (id TEXT PRIMARY KEY)`
200
+ });
201
+ /** The plain SDK's Ledgers, for `conformanceOf({ engine, ledgers: plainLedgers, skip })`: every engine must pass the suite on both SDKs. */
202
+ const plainLedgers = {
203
+ intruding: plainLedgerIntruding,
204
+ live: plainLedgerLayer({ [entriesVersion]: createEntries }),
205
+ patched: plainLedgerLayer({ [entriesVersion]: createEntries }, {
206
+ job: doublingRelease,
207
+ ledger: PatchedLedger
208
+ }),
209
+ withNotes: plainLedgerLayer({
210
+ [entriesVersion]: createEntries,
211
+ [notesVersion]: createNotes
212
+ })
213
+ };
214
+ export { plainLedgers };
@@ -0,0 +1,8 @@
1
+ import { Schema } from "effect";
2
+ declare const RejectedError_base: Schema.Class<RejectedError, Schema.TaggedStruct<"RejectedError", {
3
+ readonly reason: Schema.Unknown;
4
+ }>, import("effect/Cause").YieldableError & {
5
+ readonly brand: unique symbol;
6
+ }>;
7
+ export declare class RejectedError extends RejectedError_base {}
8
+ export {};
@@ -0,0 +1,4 @@
1
+ import { Schema } from "effect";
2
+ // src/rejected.errors.ts
3
+ var RejectedError = class extends Schema.TaggedError()("RejectedError", { reason: Schema.Unknown }) {};
4
+ export { RejectedError };