@meantjs/cli 0.0.0-bootstrap → 0.0.0-stage
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -513
- package/package.json +4 -47
- package/CHANGELOG.md +0 -733
- package/LICENSE +0 -202
- package/bin/cli.js +0 -762
- package/lib/index.d.ts +0 -521
- package/lib/index.js +0 -131
- package/wasm/candid_core_wasm.js +0 -291
- package/wasm/candid_core_wasm_bg.wasm +0 -0
package/CHANGELOG.md
DELETED
|
@@ -1,733 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
What changed between released versions of `@meantjs/cli`, which was
|
|
4
|
-
published as `@candid-core/cli`, with the command `candid-core-cli`, through
|
|
5
|
-
0.4.0; the entries for those releases name them so. This file ships inside
|
|
6
|
-
the published tarball, so the record travels with the artifact.
|
|
7
|
-
|
|
8
|
-
**Every entry names the exact revisions it embeds** — the compiler crate
|
|
9
|
-
(`meant` from 0.4.0's entry on, published as `candid-core` before) and the
|
|
10
|
-
`candid-core-ts` generator are compiled into the wasm artifact from one
|
|
11
|
-
repository commit, and the pairing is the artifact's
|
|
12
|
-
provenance: the parity gates prove the emitted module and contract are
|
|
13
|
-
byte-identical to that commit's Rust-native outputs over the golden
|
|
14
|
-
fixtures.
|
|
15
|
-
|
|
16
|
-
`@meantjs/cli` is pre-1.0. Until 1.0 any release may change the CLI
|
|
17
|
-
grammar, the library API, and the request/response shapes. Pin an exact
|
|
18
|
-
version.
|
|
19
|
-
|
|
20
|
-
## 0.5.0 — 2026-11-01
|
|
21
|
-
|
|
22
|
-
Embeds `meant` 0.1.0 and the `candid-core-ts` generator from the repository
|
|
23
|
-
commit the release is dispatched from; the release record names the exact
|
|
24
|
-
SHA. The dispatched commit's `meant` source is ahead of the crates.io 0.1.0
|
|
25
|
-
archive by two changes, and neither moves a Contract or an identity: the
|
|
26
|
-
reader of doc attributes behind `didToDocAttributes`, which 0.4.0 embedded
|
|
27
|
-
already, and type-depth walks that allocate the same way for the same input
|
|
28
|
-
whatever the heap layout, refusing and returning what they did before. So no
|
|
29
|
-
crate release comes first.
|
|
30
|
-
|
|
31
|
-
**The first release under the name `@meantjs/cli`.** Through 0.4.0 this
|
|
32
|
-
package was published as `@candid-core/cli`, with the command
|
|
33
|
-
`candid-core-cli`. 0.5.0 is 0.4.0's code under new names: the package is
|
|
34
|
-
`@meantjs/cli`, its one command is `meant`, the name of the Rust binary,
|
|
35
|
-
and the modules it writes import `@meantjs/schema`, the new name of
|
|
36
|
-
`@candid-core/schema`. The packages moved to the `@meantjs` scope beside the
|
|
37
|
-
profile packages, so that the project ships under two names: ic-reactor, for
|
|
38
|
-
the Internet Computer, and Meant, which is not tied to one chain.
|
|
39
|
-
`@candid-core/cli` keeps every version it published and gets no new one.
|
|
40
|
-
|
|
41
|
-
A stable release, published under the npm `latest` dist-tag; keep it pinned,
|
|
42
|
-
`npm install --save-dev --save-exact @meantjs/cli`. Run it as
|
|
43
|
-
`npx @meantjs/cli gen …`, or as `meant gen …` from a script in your
|
|
44
|
-
`package.json`. Never as a bare `npx meant`: the unscoped `meant` package on
|
|
45
|
-
npm belongs to another author, so where this package is not installed, npx
|
|
46
|
-
would offer to download and run that one. In a shell, a bare `meant` runs
|
|
47
|
-
whichever `meant` comes first on the `PATH`, which can be the Rust binary from
|
|
48
|
-
`cargo install meant`, whose commands are `compile` and `validate`; a script
|
|
49
|
-
in `package.json` puts this package's command first. The optional peer is
|
|
50
|
-
`@meantjs/schema` at exactly `0.6.0`, which is `@candid-core/schema` 0.5.0's
|
|
51
|
-
code under its new name; install the two together, each at its exact
|
|
52
|
-
version.
|
|
53
|
-
|
|
54
|
-
**Upgrading from `@candid-core/cli` 0.4.0 changes names, and the first two
|
|
55
|
-
lines of every module.** Install `@meantjs/cli` and `@meantjs/schema` in
|
|
56
|
-
place of the old pair, replace `candid-core-cli` with `meant` in your
|
|
57
|
-
scripts, and replace `@candid-core/cli` with `@meantjs/cli` where you import
|
|
58
|
-
the library. Then run `meant gen` again over every committed module: each
|
|
59
|
-
module's header line becomes
|
|
60
|
-
`// Generated by Meant from a Meant Contract. Do not edit.` and its import
|
|
61
|
-
`import * as $ from "@meantjs/schema";`, and nothing else in it changes. Until
|
|
62
|
-
then `meant gen --check` reports each module 0.4.0 wrote as drifted, exit 1.
|
|
63
|
-
The envelopes do not change. Measured over the repository's 44 tracked
|
|
64
|
-
`.did` files: both releases compile the same 40 and refuse the other 4 with
|
|
65
|
-
the same diagnostics, the 40 envelopes are byte-identical, and the 40 modules
|
|
66
|
-
differ in those two lines alone.
|
|
67
|
-
|
|
68
|
-
**What keeps the old name.** The strings inside Contract documents are not
|
|
69
|
-
package names, and this release changes none of them: the `format`
|
|
70
|
-
`candid-core`, the canonical form `candid-core-canon-1`, the
|
|
71
|
-
`candid-core:contract:v1:sha256:…` and `candid-core:interface:v1:sha256:…`
|
|
72
|
-
identities that `gen`, `project` and `check` print, and the
|
|
73
|
-
`org.candid-core.field-names/v1` extension of every envelope. The two
|
|
74
|
-
identity prefixes are hashed into every identity, so renaming them would
|
|
75
|
-
move every `contract_id` and `interface_id`. The `--json` documents keep
|
|
76
|
-
`schemaVersion` 1.
|
|
77
|
-
|
|
78
|
-
### Changed
|
|
79
|
-
|
|
80
|
-
- **BREAKING: the package is `@meantjs/cli`, and its command is `meant`.**
|
|
81
|
-
The package installs one bin, `meant`, where it installed
|
|
82
|
-
`candid-core-cli`, and the usage text names it:
|
|
83
|
-
`usage: meant gen <service.did>... [-o <dir>] [--json] [--check]`, with
|
|
84
|
-
`meant project` and `meant check` on the lines below. The grammar, the
|
|
85
|
-
exit codes and the `--json` documents are 0.4.0's. Import the library from
|
|
86
|
-
`@meantjs/cli`; its exports and their declarations are 0.4.0's.
|
|
87
|
-
- **BREAKING: generated modules import `@meantjs/schema`**, and their header
|
|
88
|
-
line is `// Generated by Meant from a Meant Contract. Do not edit.`; it was
|
|
89
|
-
`// Generated by candid-core-ts from a candid-core Contract. Do not edit.`
|
|
90
|
-
`didToModule` returns the same text. A module's other lines are unchanged.
|
|
91
|
-
- The optional peer is `@meantjs/schema` at exactly `0.6.0`, where it was
|
|
92
|
-
`@candid-core/schema` at exactly `0.5.0`.
|
|
93
|
-
- `repository` and `homepage` in `package.json` name
|
|
94
|
-
`https://github.com/B3Pay/Meant`, where the repository moved on
|
|
95
|
-
2026-10-28; GitHub redirects the old address.
|
|
96
|
-
|
|
97
|
-
## 0.4.0 — 2026-10-27
|
|
98
|
-
|
|
99
|
-
Embeds `meant` 0.1.0 and the `candid-core-ts` generator from the repository
|
|
100
|
-
commit the release is dispatched from; the release record names the exact
|
|
101
|
-
SHA. `meant` is the compiler crate formerly published as `candid-core`, and
|
|
102
|
-
`meant` 0.1.0 is `candid-core` 0.1.0's code under the new name: the crate's
|
|
103
|
-
first version without a prerelease suffix. The dispatched commit's `meant`
|
|
104
|
-
source is ahead of the crates.io 0.1.0 archive by one change, the reader of
|
|
105
|
-
doc attributes behind `didToDocAttributes` (below), which moves no Contract
|
|
106
|
-
and no identity, so no crate release comes first.
|
|
107
|
-
|
|
108
|
-
A stable release, published under the npm `latest` dist-tag, so a plain
|
|
109
|
-
`npx @candid-core/cli` runs it; keep it pinned,
|
|
110
|
-
`npm install --save-dev --save-exact @candid-core/cli`. A `^0.3.0` range does
|
|
111
|
-
not admit it. The `beta` dist-tag stays on 0.2.0-beta.1. The optional peer is
|
|
112
|
-
`@candid-core/schema` at exactly `0.5.0` (exactly `0.4.0` in 0.3.0), and npm
|
|
113
|
-
refuses a mismatched pair (`ERESOLVE could not resolve`), so move the two
|
|
114
|
-
packages together.
|
|
115
|
-
|
|
116
|
-
Against the compiler 0.3.0 embeds (`candid-core` 0.1.0-beta.3 and five later
|
|
117
|
-
changes), three things change. A record field whose id is 4294967295, written
|
|
118
|
-
as that number or as a name that hashes to it, is refused with
|
|
119
|
-
`did_parse_error`; 0.3.0's compiler numbered the field after it 0. Collecting
|
|
120
|
-
the provenance sidecar no longer grows with the square of the declarations,
|
|
121
|
-
so a large `.did` file compiles in time proportional to its size. And every
|
|
122
|
-
envelope `gen` writes names `meant` 0.1.0 as its producer, where 0.3.0's
|
|
123
|
-
named `candid-core` 0.1.0-beta.3, so `gen --check` reports each envelope
|
|
124
|
-
0.3.0 wrote as drifted, exit 1, until `gen` runs again. Every other input
|
|
125
|
-
compiles to the same Contract and identities: of the repository's 44 tracked
|
|
126
|
-
`.did` files, the 40 that both releases compile give envelopes that differ in
|
|
127
|
-
the `producer` alone, and the 4 that 0.3.0 refuses this release refuses with
|
|
128
|
-
the same diagnostics.
|
|
129
|
-
|
|
130
|
-
### Added
|
|
131
|
-
|
|
132
|
-
- **`didToDocAttributes` reads `@name(…)` attributes in doc comments.** It
|
|
133
|
-
compiles the sources and returns `{ ok: true, contract, source_info,
|
|
134
|
-
doc_attributes }`: the Contract and the SourceInfo sidecar
|
|
135
|
-
`meant compile <path>` prints, which no function of this package
|
|
136
|
-
exposed before, and every documented item's prose and attributes keyed by
|
|
137
|
-
its SourceInfo path, as `docs/doc-attributes.md` specifies (doc attributes
|
|
138
|
-
v1). A malformed attribute fails the call with `doc_attribute_malformed`
|
|
139
|
-
or `doc_attribute_duplicate_key`. The declarations add `DocAttributes`,
|
|
140
|
-
`DocItem`, `DocAttribute`, `DocArgument`, `DocValue`, `SourceOrigin` and
|
|
141
|
-
`DocAttributesSuccess`. The other functions are unchanged.
|
|
142
|
-
- **`gen --json` reports each entry's identities.** Every entry that compiled
|
|
143
|
-
(`written`, `unchanged` or `drifted`, with or without `--check`) carries
|
|
144
|
-
`identities: { contract_id, interface_id }`, equal to its envelope's
|
|
145
|
-
`contract.identities` and to the lines the human report prints, under the
|
|
146
|
-
key names `project --json` and `check --json` already use. `interface_id`
|
|
147
|
-
is absent when the `.did` has no actor; a `failed` entry has no
|
|
148
|
-
`identities`. The declarations add `CliIdentities` and the optional
|
|
149
|
-
`CliEntryReport.identities`; `Identities` is unchanged, its `interface_id`
|
|
150
|
-
still required. `schemaVersion` stays `1`, since adding a field does not
|
|
151
|
-
change it. A build step no longer has to parse the envelope to learn the
|
|
152
|
-
interface identity.
|
|
153
|
-
|
|
154
|
-
### Generated modules
|
|
155
|
-
|
|
156
|
-
- **BREAKING**: a declared `blob`, `record {}` or `variant {}` names only
|
|
157
|
-
itself. Each of the three has one fixed rendering (`Uint8Array` /
|
|
158
|
-
`$.c.blob()`, `Record<string, never>` / `$.c.unit()`, `never` /
|
|
159
|
-
`$.c.variant({})`), and every use now renders it, as every use of a
|
|
160
|
-
primitive already did. Before, the alias of that shape whose name sorted
|
|
161
|
-
first, wherever it sat in the file, named every use of it: beside
|
|
162
|
-
`type Hash = blob`, a field written `memo : opt blob` read `Hash | null`
|
|
163
|
-
and its builder was `$.c.opt($Hash)`. Now it reads `Uint8Array | null`
|
|
164
|
-
with `$.c.opt($.c.blob())`, and `type Subaccount = blob` is emitted as
|
|
165
|
-
`export type Subaccount = Uint8Array`, so a field written
|
|
166
|
-
`subaccount : opt Subaccount` reads `Uint8Array | null` too. Value types,
|
|
167
|
-
wire bytes and envelopes do not change for it, and every declaration is still
|
|
168
|
-
exported under its name. A module with two aliases of one of these shapes,
|
|
169
|
-
or one alias and a plain use, changes text, so `gen --check` reports it as
|
|
170
|
-
drifted until `gen` runs again. Measured on the repository's 44 tracked
|
|
171
|
-
`.did` files against 0.3.0: of the 40 that generate, three modules change,
|
|
172
|
-
`shadowing.did`'s and the two fixtures added for this change. A
|
|
173
|
-
declaration of one of these shapes named after an export of the module
|
|
174
|
-
(`actor`) is omitted on its own and no longer takes the other uses of the
|
|
175
|
-
shape with it; `@candid-core/schema` 0.5.0's `schemaFromContract` applies
|
|
176
|
-
the same rule.
|
|
177
|
-
|
|
178
|
-
## 0.3.0 — 2026-10-10
|
|
179
|
-
|
|
180
|
-
Embeds `candid-core` 0.1.0-beta.3 and the `candid-core-ts` generator from the
|
|
181
|
-
same repository commit the release is dispatched from; the release record
|
|
182
|
-
names the exact SHA. That commit's `candid-core` source is ahead of the
|
|
183
|
-
0.1.0-beta.3 archive on crates.io by five changes not yet in a crate release:
|
|
184
|
-
the four 0.2.0 already carried (a `.did` source may begin with one UTF-8 byte
|
|
185
|
-
order mark; a run of more than 256 consecutive comments is refused; a type on
|
|
186
|
-
a cycle that passes only through `opt` is refused; the crate's Contract JSON
|
|
187
|
-
loaders refuse a struct written as a JSON array) and one more, the crate's
|
|
188
|
-
Contract JSON loaders refuse a unit variant written as a JSON map
|
|
189
|
-
(`"primitive": {"nat": null}` for `"primitive": "nat"`), which beta.3's
|
|
190
|
-
loaders accept. No input of this package reaches the last two: `gen`,
|
|
191
|
-
`project`, `check` and the four library functions read `.did` sources and
|
|
192
|
-
never load a Contract document. The embedded compiler therefore compiles
|
|
193
|
-
every `.did` as 0.2.0's does: every input both accept compiles to the same
|
|
194
|
-
Contract and identities, every envelope `gen` writes is byte-identical to
|
|
195
|
-
0.2.0's, and envelopes still name 0.1.0-beta.3 as their producer.
|
|
196
|
-
|
|
197
|
-
A stable release, published under the npm `latest` dist-tag, so a plain
|
|
198
|
-
`npx @candid-core/cli` runs it; pin it in a project,
|
|
199
|
-
`npm install --save-dev --save-exact @candid-core/cli`. The `beta` dist-tag
|
|
200
|
-
stays on 0.2.0-beta.1.
|
|
201
|
-
|
|
202
|
-
**It pairs with exactly one schema release.** The optional peer is exactly
|
|
203
|
-
`@candid-core/schema` `0.4.0` (exactly `0.3.0` in 0.2.0). Each method of the
|
|
204
|
-
`Actor` a generated module declares is typed with `$.WithMode`, which
|
|
205
|
-
`@candid-core/schema` 0.4.0 adds, so a module with an actor method does not
|
|
206
|
-
compile against 0.3.0 (`TS2694`, "has no exported member 'WithMode'", once
|
|
207
|
-
per method). npm refuses to install a mismatched pair (`ERESOLVE could not
|
|
208
|
-
resolve`). Install the pair at exact versions, together.
|
|
209
|
-
|
|
210
|
-
**Upgrading from 0.2.0.** Two changes break something, each marked
|
|
211
|
-
**BREAKING** below, and both are about generated modules: the peer moves to
|
|
212
|
-
`@candid-core/schema` 0.4.0, which a module with an actor method needs; and
|
|
213
|
-
the text of every generated module with a declaration or an actor changes,
|
|
214
|
-
so `gen --check` reports each module 0.2.0 wrote as drifted (exit 1) until
|
|
215
|
-
you run `gen` again. Upgrade both packages in one step and regenerate.
|
|
216
|
-
Envelopes do not change. Code that imports the generated names keeps
|
|
217
|
-
compiling, with one exception: type-level code that compares a method type
|
|
218
|
-
of `Actor` for exact equality, such as an `Equal<A, B>` test helper, now
|
|
219
|
-
sees the `WithMode` intersection. The commands `project` and `check`, the
|
|
220
|
-
library functions `projectDid` and `checkCompatible`, and their types are
|
|
221
|
-
additive; `gen`, `didToContract` and `didToModule` keep their grammar,
|
|
222
|
-
signatures and results but for the module text.
|
|
223
|
-
|
|
224
|
-
### Added
|
|
225
|
-
|
|
226
|
-
- **`candid-core-cli project <in.did> --methods <a,b,...> -o <out.did>`**
|
|
227
|
-
writes a `.did` holding only the methods named and every declaration they
|
|
228
|
-
reach, as one self-contained file, and prints the interface identities of
|
|
229
|
-
the input and of the projection. The output is deterministic: the same
|
|
230
|
-
input and the same set of names give the same bytes, in any order. It
|
|
231
|
-
keeps declaration names, doc comments (a tuple element's included: a
|
|
232
|
-
tuple with a documented element is written one element per line) and
|
|
233
|
-
argument names, so `gen` on the projection emits the same declarations,
|
|
234
|
-
docs and modes as on the full interface, with an `Actor` that lists only
|
|
235
|
-
the projected methods. A service class's init arguments are dropped. An
|
|
236
|
-
unknown method name fails with `unknown_method`, one per distinct name,
|
|
237
|
-
the first listing the service's methods in its `notes`, once; an empty
|
|
238
|
-
list (`--methods ""`) with `empty_method_list`, a source with no service
|
|
239
|
-
with `no_service`; each exits 1 and writes nothing. The unknown-method
|
|
240
|
-
diagnostics are bounded at 4 MiB in all, each counted as the JSON writes
|
|
241
|
-
it (the list of methods aside), the names past that bound counted in one
|
|
242
|
-
`resource_limit_exceeded` diagnostic (`projection_diagnostic_bytes`)
|
|
243
|
-
instead of reported. A projection is at
|
|
244
|
-
most 1 MiB, the compiler's bound on one source, since it is compiled
|
|
245
|
-
again: a larger one fails with `resource_limit_exceeded`
|
|
246
|
-
(`projection_bytes`), exit 1, as soon as writing it reaches that bound.
|
|
247
|
-
Every name, requested or reached, is found by binary search among names
|
|
248
|
-
sorted once. Methods are written in name order, a service import's among
|
|
249
|
-
the entry's. `-o` is required, and may not be, or become, a source of the
|
|
250
|
-
input (the entry or any `.did` beneath its directory, which `project` reads
|
|
251
|
-
as `gen` does): naming one of those files by any path, symlink or hard
|
|
252
|
-
link, or a new `.did` beneath that directory, fails with
|
|
253
|
-
`output_is_input`, exit 1, and writes nothing. An output that cannot be
|
|
254
|
-
read or written fails with `output_write_failed` (its `notes` hold the
|
|
255
|
-
system error code), exit 1; an existing output of another size is
|
|
256
|
-
replaced without being read. `--json` prints one document instead of the
|
|
257
|
-
report, and `{ ok: false, diagnostics }` for every failure.
|
|
258
|
-
- **`candid-core-cli check <written.did> --against <live.did>`** exits 0
|
|
259
|
-
when the live interface is still a Candid subtype of the written one, and
|
|
260
|
-
1 otherwise: every written method must exist in the live service with the
|
|
261
|
-
same mode, its arguments contravariant and its results covariant, and
|
|
262
|
-
methods only the live service has are ignored. Each finding names its
|
|
263
|
-
method and a stable code (`method_missing`, `mode_changed`,
|
|
264
|
-
`method_incompatible`, the warning `special_opt_rule`, and
|
|
265
|
-
`resource_limit_exceeded`) and, inside a type, the path where the check
|
|
266
|
-
failed. A `special_opt_rule` warning is reported at every path that
|
|
267
|
-
decodes as `null` along which no pair of types repeats, a shared type
|
|
268
|
-
under each path that reaches it. Past 1,000 warnings a method reports the
|
|
269
|
-
first 1,000 and a `resource_limit_exceeded` warning; its verdict stands.
|
|
270
|
-
A method whose check reaches its depth or work bound fails closed; work
|
|
271
|
-
is counted in steps, each one unit of work done (a pair of types visited,
|
|
272
|
-
a field, arm, method or value examined or passed over, a path segment a
|
|
273
|
-
warning or a failure copies or a warning re-examines). A step reads no
|
|
274
|
-
name: service methods are paired by ranks computed once per check and a
|
|
275
|
-
field's name is read by its position, so a step's cost does not grow with
|
|
276
|
-
the length of the names: it does a bounded amount of work, and its
|
|
277
|
-
lookups in the maps of type pairs the walk keeps take time logarithmic in
|
|
278
|
-
their size. The
|
|
279
|
-
check as a whole is bounded too, so many methods sharing one type cannot
|
|
280
|
-
multiply the per-method bounds: 10,000,000 steps (one more per method),
|
|
281
|
-
10,000 `special_opt_rule` warnings and 4 MiB of reported diagnostics, each
|
|
282
|
-
counted as the JSON response writes it, keys and indentation included, in
|
|
283
|
-
all (`check_total_steps`, `check_total_warnings`, `check_output_bytes`);
|
|
284
|
-
a diagnostic is measured only up to the first string that passes the byte
|
|
285
|
-
bound, so long names cannot make the measuring itself slow. So the walk's
|
|
286
|
-
time grows with its steps (times that logarithm) and the reported
|
|
287
|
-
diagnostics' with their bytes; compiling both sides, within the
|
|
288
|
-
compiler's own limits, and ranking the method names are done once per
|
|
289
|
-
check, before the walk. Methods are checked in name order; when the step
|
|
290
|
-
or warning bound is reached, that method and every method after it get
|
|
291
|
-
one `resource_limit_exceeded` error each and nothing else. Those count
|
|
292
|
-
against the 4 MiB like any other diagnostic, and once a method's
|
|
293
|
-
diagnostics would pass it, that method and every method after it are
|
|
294
|
-
counted in one last `resource_limit_exceeded` error
|
|
295
|
-
(`check_output_bytes`), which names no method and holds the count in
|
|
296
|
-
`unreported_methods`. Either way the check exits 1, and a response is at
|
|
297
|
-
most 4 MiB and 1,016 bytes, however many methods the written side has.
|
|
298
|
-
Below these bounds a method's findings do not depend on the other
|
|
299
|
-
methods. The report prints the live interface identity, so an unchanged
|
|
300
|
-
interface can be told from one that changed compatibly.
|
|
301
|
-
- **`projectDid(sources, methods)` and `checkCompatible(written, live)`**,
|
|
302
|
-
the library functions behind the two commands, exported beside
|
|
303
|
-
`didToContract` and `didToModule`, with their types (`ProjectionSuccess`,
|
|
304
|
-
`CompatibilityReport`, `CompatibilityDiagnostic`, whose `method` is absent
|
|
305
|
-
only on the `check_output_bytes` diagnostic and whose
|
|
306
|
-
`unreported_methods` is present only there, `CheckFailure`,
|
|
307
|
-
`Identities`). Neither fetches anything; the package still has no runtime
|
|
308
|
-
dependencies.
|
|
309
|
-
|
|
310
|
-
### Changed
|
|
311
|
-
|
|
312
|
-
- **The usage text lists the three commands.** A usage error still exits 64
|
|
313
|
-
with the usage on stderr and nothing on stdout; its text now has three
|
|
314
|
-
lines, one per command.
|
|
315
|
-
|
|
316
|
-
### Generated modules
|
|
317
|
-
|
|
318
|
-
- **Compiler errors name the types you import.** A generated module now
|
|
319
|
-
declares each declaration's type under its Candid name and keeps the
|
|
320
|
-
`$`-prefixed local for the schema value only, so an app's TypeScript errors
|
|
321
|
-
read `Account` and `Actor`, the names it imports, where they read
|
|
322
|
-
`$Account` and `$Actor`:
|
|
323
|
-
|
|
324
|
-
```ts
|
|
325
|
-
export type Account = { owner: $.Principal; subaccount: Uint8Array | null };
|
|
326
|
-
const $Account: $.Schema<Account> = $.c.rec(() => $.c.record({ … }));
|
|
327
|
-
export { $Account as Account };
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
Every export name, and what each one is as a type and as a value, is
|
|
331
|
-
unchanged, and so is every module's set of declarations. A name that
|
|
332
|
-
cannot be a type in the module keeps the `$` local for its type too: a
|
|
333
|
-
global type the generated types use (`Array`, `Record`, `Uint8Array`,
|
|
334
|
-
`Promise`), and a word TypeScript refuses as a type's name (`delete`,
|
|
335
|
-
`string`, `default`, `keyof`, `readonly`, …). So `type $Array = …` still
|
|
336
|
-
appears, and errors about it still name `$Array`. Code that imports the
|
|
337
|
-
generated names is unaffected; code that parses or patches the generated
|
|
338
|
-
source must follow the new text.
|
|
339
|
-
- **BREAKING**: the text of every generated module with a declaration or an
|
|
340
|
-
actor changes, by the item above and the one below, so `gen --check`
|
|
341
|
-
against a module 0.2.0 wrote reports it as drifted, exit 1, until `gen`
|
|
342
|
-
runs again. Measured on the repository's 41 tracked `.did` files: the 37
|
|
343
|
-
that generate give a different module and a byte-identical envelope.
|
|
344
|
-
- **Each `Actor` method carries its mode.** `gen` and `didToModule` now emit
|
|
345
|
-
each method of `Actor` as its call signature intersected with
|
|
346
|
-
`$.WithMode<mode>` (`"query"`, `"composite_query"`, `"update"` or
|
|
347
|
-
`"oneway"`), which `@candid-core/schema`'s `ModeOf` reads back, so a call
|
|
348
|
-
layer can tell a query from an update at compile time:
|
|
349
|
-
|
|
350
|
-
```ts
|
|
351
|
-
export type Actor = {
|
|
352
|
-
icrc1_balance_of: ((arg0: Account) => Promise<bigint>) & $.WithMode<"query">;
|
|
353
|
-
icrc1_transfer: ((arg0: TransferArg) => Promise<TransferResult>) & $.WithMode<"update">;
|
|
354
|
-
};
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
The call signatures, the method names and the module's exports are
|
|
358
|
-
unchanged, and an actor with no methods still generates an empty `Actor`.
|
|
359
|
-
Type-level code that compares a method type for exact equality sees the
|
|
360
|
-
intersection; `Parameters<>` and `ReturnType<>` do not.
|
|
361
|
-
- **BREAKING**: `WithMode` is new in `@candid-core/schema` 0.4.0, so a
|
|
362
|
-
module with an actor method needs that release: against 0.3.0 it fails to
|
|
363
|
-
compile with `TS2694` ("has no exported member 'WithMode'"), once per
|
|
364
|
-
method. The peer moves to exactly `0.4.0` for this reason.
|
|
365
|
-
|
|
366
|
-
## 0.2.0 — 2026-10-06
|
|
367
|
-
|
|
368
|
-
Embeds `candid-core` 0.1.0-beta.3 and the `candid-core-ts` generator from the
|
|
369
|
-
same repository commit the release is dispatched from; the release record
|
|
370
|
-
names the exact SHA. That commit's `candid-core` source is ahead of the
|
|
371
|
-
0.1.0-beta.3 archive on crates.io by four changes not yet in a crate release:
|
|
372
|
-
a `.did` source may begin with one UTF-8 byte order mark, which beta.3 refuses
|
|
373
|
-
with "Unknown token"; a run of more than 256 consecutive comments between two
|
|
374
|
-
tokens is refused with `resource_limit_exceeded` (below), which beta.3
|
|
375
|
-
compiles up to a stack-dependent length and then aborts on; a type on a cycle
|
|
376
|
-
that passes only through `opt` is refused with `did_type_check_error`
|
|
377
|
-
(below), which beta.3 compiles; and the crate's Contract JSON loaders refuse
|
|
378
|
-
a struct written as a JSON array, which beta.3's loaders accept. No input of
|
|
379
|
-
this package reaches the last one: `gen`, `didToContract` and `didToModule`
|
|
380
|
-
read `.did` sources and never load a Contract document. Every input both
|
|
381
|
-
accept compiles to the same Contract and identities, and envelopes still name
|
|
382
|
-
0.1.0-beta.3 as their producer.
|
|
383
|
-
|
|
384
|
-
`@candid-core/schema` 0.3 breaks the 0.2 API (principal values are canonical text, collapsing opts are boxed, every `vec nat8` is a `Uint8Array`, generated modules use a new binding layout and may omit declarations, and the `./actor`, `./transport-icp`, `./forms` and `./labels` subpaths are gone); there is no compatibility layer.
|
|
385
|
-
|
|
386
|
-
The first stable release of the 0.2 line. It is published under the npm
|
|
387
|
-
`latest` dist-tag, so a plain `npx @candid-core/cli` runs it; pin it in a
|
|
388
|
-
project, `npm install --save-dev --save-exact @candid-core/cli`. The `beta`
|
|
389
|
-
dist-tag stays on 0.2.0-beta.1.
|
|
390
|
-
|
|
391
|
-
**It pairs with exactly one schema release.** The optional peer is exactly
|
|
392
|
-
`@candid-core/schema` `0.3.0` (`^0.2.0` in 0.1.0, exactly `0.3.0-beta.1` in
|
|
393
|
-
0.2.0-beta.1). The modules this generator emits need that release's
|
|
394
|
-
`Principal` export and boxed options, which 0.2.0 does not have, and the
|
|
395
|
-
generator and that release's `schemaFromContract` agree on blobs and on
|
|
396
|
-
omitted declarations only when both come from the same release. npm refuses
|
|
397
|
-
to install a mismatched pair (measured with npm 11.3.0: `ERESOLVE could not
|
|
398
|
-
resolve`, exit status 1); the 0.2.0-beta.1 entry below says npm only warns,
|
|
399
|
-
which was wrong for a published peer. Install the pair at exact versions.
|
|
400
|
-
|
|
401
|
-
**Upgrading from 0.1.0.** 0.2.0 is 0.2.0-beta.1 plus the changes in this
|
|
402
|
-
entry, so the upgrade is this entry and the 0.2.0-beta.1 entry below, read
|
|
403
|
-
together. Every break in either is marked **BREAKING**: from 0.2.0-beta.1, the
|
|
404
|
-
`$` binding layout, `$.Principal`, boxed collapsing opts, a declared primitive
|
|
405
|
-
naming only itself and every `vec nat8` typed `Uint8Array`, and omission in
|
|
406
|
-
place of refusal (`gen`'s exit status and `didToModule`'s result); from this
|
|
407
|
-
entry, the refusals of a long comment run and of a type on a cycle through
|
|
408
|
-
`opt` alone. JSDoc from `.did` doc comments and
|
|
409
|
-
`gen`'s several entries, `--json` and `--check` are additive. The library's
|
|
410
|
-
three functions keep their names and signatures, and `lib/index.d.ts` and the
|
|
411
|
-
command grammar are unchanged since 0.2.0-beta.1.
|
|
412
|
-
|
|
413
|
-
### A long run of comments is refused with a resource diagnostic
|
|
414
|
-
|
|
415
|
-
The embedded compiler now refuses a `.did` file with more than 256 consecutive
|
|
416
|
-
comments between two tokens. The upstream Candid tokenizer it embeds spends one
|
|
417
|
-
stack frame on each comment it skips, so the compiler counts the run first,
|
|
418
|
-
without recursing, and refuses an over-long one before that tokenizer runs.
|
|
419
|
-
Before, a long enough run exhausted the WebAssembly stack: measured with the
|
|
420
|
-
published tarballs (Node 24.2, macOS arm64), 0.2.0-beta.1's `gen` compiled a
|
|
421
|
-
file with 2 728 consecutive `//` lines and failed at 2 729 with
|
|
422
|
-
`internal_error` "Maximum call stack size exceeded", and 0.1.0's compiled
|
|
423
|
-
2 825 and crashed at 2 826 with an uncaught `RangeError`; the threshold moves
|
|
424
|
-
with the toolchain and the engine.
|
|
425
|
-
|
|
426
|
-
- **BREAKING (input)**: this refuses files that `gen` accepted before: any
|
|
427
|
-
`.did` in the bundle with a run of 257 to about 2 700 or 2 800 comments,
|
|
428
|
-
such as a license header written as `//` lines. `gen`, `didToContract` and
|
|
429
|
-
`didToModule` report `resource_limit_exceeded` with resource
|
|
430
|
-
`source_nesting`, limit 256 and `observed` 257, through the existing
|
|
431
|
-
diagnostic path (the `{ ok: false, diagnostics }` document, or `--json`)
|
|
432
|
-
with exit status 1. A longer run, which failed with `internal_error` before
|
|
433
|
-
(an uncaught `RangeError` in 0.1.0), gets the same diagnostic. The CLI
|
|
434
|
-
compiles at the compiler's default limits and has no flag to raise this one:
|
|
435
|
-
write such a header as a single `/* */` block, which counts as one comment,
|
|
436
|
-
or shorten it. Line and block comments count alike;
|
|
437
|
-
blank lines between comments do not end a run, any token does, a nested
|
|
438
|
-
block comment counts once, and comment markers inside a string are not
|
|
439
|
-
comments.
|
|
440
|
-
- **Nothing else moves.** A file within the limit generates the same module and
|
|
441
|
-
the same envelope, with the same identities and documentation, as before.
|
|
442
|
-
|
|
443
|
-
### The embedded generator renders on an explicit stack
|
|
444
|
-
|
|
445
|
-
- The embedded `candid-core-ts` generator keeps its pending work on an explicit
|
|
446
|
-
stack instead of recursing once per type level, so generation uses constant
|
|
447
|
-
call-stack depth in the Contract's nesting. It also refuses a Contract with a
|
|
448
|
-
cycle that passes through no declared node, which a TypeScript type alias
|
|
449
|
-
cannot spell. No `.did` source produces such a Contract (a recursive Candid
|
|
450
|
-
type needs a name), so no input `gen` accepts is affected: every module it
|
|
451
|
-
writes is byte-identical to what 0.2.0-beta.1 writes for the same input, and
|
|
452
|
-
`didToModule`, which takes `.did` sources, returns the same result.
|
|
453
|
-
|
|
454
|
-
### A type on a cycle through `opt` alone is refused
|
|
455
|
-
|
|
456
|
-
The embedded compiler now refuses a type that lies on a cycle passing only
|
|
457
|
-
through `opt`: `type T = opt T;`, `type T = opt opt T;`,
|
|
458
|
-
`type A = opt B; type B = opt A;`, or the same through an alias. Decoding a
|
|
459
|
-
value that is not an `opt` at such a type unwraps `opt` without end, so no
|
|
460
|
-
decoder can answer for it; a generated schema for it ended in a depth refusal.
|
|
461
|
-
|
|
462
|
-
- **BREAKING (input)**: this refuses files that `gen` accepted before:
|
|
463
|
-
`gen`, `didToContract` and `didToModule` report `did_type_check_error`,
|
|
464
|
-
naming the type ("type T lies on a cycle that passes only through opt;
|
|
465
|
-
…"), through the existing diagnostic path (the `{ ok: false,
|
|
466
|
-
diagnostics }` document, or `--json`) with exit status 1, and write nothing
|
|
467
|
-
for that entry. The upstream Candid checker accepts these files; the
|
|
468
|
-
refusal is candid-core's own. 0.1.0 refused them too, with
|
|
469
|
-
`ts_generation_refused` at generation, because each such type wraps `opt`
|
|
470
|
-
in `opt`; 0.2.0-beta.1 generates them, boxed.
|
|
471
|
-
- **A cycle with any other constructor on it still compiles**: `type L = opt
|
|
472
|
-
record { head : nat; tail : L }`, `type T = opt vec T`, `type T = record {
|
|
473
|
-
a : opt T }`, `type T = opt variant { a : T }`.
|
|
474
|
-
- **Nothing else moves.** Every other file generates the same module and the
|
|
475
|
-
same envelope, with the same identities and documentation, as before.
|
|
476
|
-
|
|
477
|
-
## 0.2.0-beta.1 — 2026-10-02
|
|
478
|
-
|
|
479
|
-
Embeds `candid-core` 0.1.0-beta.3 and the `candid-core-ts` generator from the
|
|
480
|
-
same repository commit the release is dispatched from; the release record
|
|
481
|
-
names the exact SHA. That commit's `candid-core` source is ahead of the
|
|
482
|
-
0.1.0-beta.3 archive on crates.io by one change not yet in a crate release: a
|
|
483
|
-
`.did` source may begin with one UTF-8 byte order mark, which beta.3 refuses
|
|
484
|
-
with "Unknown token". Every input beta.3 accepts compiles to the same Contract
|
|
485
|
-
and identities, and envelopes still name 0.1.0-beta.3 as their producer.
|
|
486
|
-
|
|
487
|
-
`@candid-core/schema` 0.3 betas break the 0.2 API (principal values are canonical text, collapsing opts are boxed, every `vec nat8` is a `Uint8Array`, generated modules use a new binding layout and may omit declarations, and the `./actor`, `./transport-icp`, `./forms` and `./labels` subpaths are gone); there is no compatibility layer.
|
|
488
|
-
|
|
489
|
-
The first beta of the 0.2 line, and the first prerelease of this package. It is
|
|
490
|
-
published under the npm `beta` dist-tag, so `latest` stays on 0.1.0; ask for it
|
|
491
|
-
by its exact version, `npm install --save-exact @candid-core/cli@0.2.0-beta.1`,
|
|
492
|
-
or run it as `npx @candid-core/cli@0.2.0-beta.1`.
|
|
493
|
-
|
|
494
|
-
**It pairs with exactly one schema release.** The optional peer moves from
|
|
495
|
-
`@candid-core/schema` `^0.2.0` to exactly `0.3.0-beta.1`. The modules this
|
|
496
|
-
generator emits need that release's `Principal` export and boxed options, which
|
|
497
|
-
0.2.0 does not have, and the generator and that release's `schemaFromContract`
|
|
498
|
-
agree on blobs and on omitted declarations only when both come from the same
|
|
499
|
-
release. While the two packages move in lockstep, every `@candid-core/schema`
|
|
500
|
-
beta is paired with a new beta of this package that raises the exact peer.
|
|
501
|
-
Because the peer is optional, npm does not refuse a mismatched pair: it warns
|
|
502
|
-
`ERESOLVE overriding peer dependency` and installs anyway, and the result does
|
|
503
|
-
not type-check. Install the pair at exact versions.
|
|
504
|
-
|
|
505
|
-
Every break below is marked **BREAKING**, ordered for a reader upgrading from
|
|
506
|
-
0.1.0: what the emitted module looks like, then what it emits for interfaces it
|
|
507
|
-
used to refuse, then the command line. The library's three functions keep
|
|
508
|
-
their names and signatures.
|
|
509
|
-
|
|
510
|
-
### Generated modules bind `$`-prefixed locals
|
|
511
|
-
|
|
512
|
-
The embedded generator changes the layout of every module it emits. A module
|
|
513
|
-
imports the schema runtime as a namespace and binds each declaration as a local
|
|
514
|
-
whose name starts with `$`, exported under its Candid name:
|
|
515
|
-
|
|
516
|
-
```ts
|
|
517
|
-
import * as $ from "@candid-core/schema";
|
|
518
|
-
|
|
519
|
-
type $Tokens = { e8s: bigint };
|
|
520
|
-
const $Tokens: $.Schema<$Tokens> = $.c.rec(() => $.c.record({ e8s: $.c.nat64 }));
|
|
521
|
-
export { $Tokens as Tokens };
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
- **BREAKING**: the text of every generated module changes. `import
|
|
525
|
-
{ Tokens, actor, type Actor } from "./ledger"` resolves exactly as before,
|
|
526
|
-
so code that imports the generated names is unaffected by the layout;
|
|
527
|
-
code that parses or patches the generated source, or relied on its
|
|
528
|
-
module-scope names (`export type X`, `export const X`, the `c` and `Schema`
|
|
529
|
-
bindings, the separate `import type { PrincipalValue }` line), must follow
|
|
530
|
-
the new layout.
|
|
531
|
-
- **BREAKING**: declarations the generator used to refuse with
|
|
532
|
-
`ts_generation_refused` now generate: names that collided with the module's
|
|
533
|
-
own bindings (`c`, `Schema`, `PrincipalValue`), with the global types its
|
|
534
|
-
lowerings use (`Array`, `Record`, `Uint8Array`, `Promise`), or that are
|
|
535
|
-
TypeScript reserved words (`delete`, `string`). Import them by name,
|
|
536
|
-
renaming where needed (`import { delete as del } from "./service"`). A
|
|
537
|
-
declaration named `default` becomes the module's default export.
|
|
538
|
-
- Declarations named `actor` or `Actor` stay reserved: those are the
|
|
539
|
-
module's own export names. They are omitted from the module rather than
|
|
540
|
-
refusing it; see "Unrepresentable declarations are omitted, not refused".
|
|
541
|
-
|
|
542
|
-
### Generated modules type principals as `$.Principal`
|
|
543
|
-
|
|
544
|
-
- **BREAKING**: the embedded generator emits `$.Principal` wherever it
|
|
545
|
-
emitted `$.PrincipalValue`: principal fields, func reference aliases
|
|
546
|
-
(`{ principal: $.Principal; method: string }`), service aliases, and the
|
|
547
|
-
`actor` schema (`$.Schema<$.Principal>`). The paired `@candid-core/schema`
|
|
548
|
-
release replaces `PrincipalValue` (`{ toText(): string }`) with
|
|
549
|
-
`Principal`, canonical principal text as a branded string: a decoded
|
|
550
|
-
principal is that text, and encoding accepts only it, so an SDK `Principal`
|
|
551
|
-
converts once with `principal(sdkPrincipal)`.
|
|
552
|
-
- A declaration named `Principal` still generates, bound as `$Principal` and
|
|
553
|
-
exported as `Principal`.
|
|
554
|
-
|
|
555
|
-
### Options whose inner type admits `null` are boxed
|
|
556
|
-
|
|
557
|
-
- **BREAKING**: the embedded `candid-core-ts` generator no longer refuses an
|
|
558
|
-
`opt` whose inner type is another `opt`, `null`, or `reserved` (its
|
|
559
|
-
`TsGenError::UnrepresentableOption` is removed). Such declarations now
|
|
560
|
-
generate, with the present value boxed: `opt opt nat` emits
|
|
561
|
-
`{ some: bigint | null } | null` with builder `$.c.opt($.c.opt($.c.nat))`.
|
|
562
|
-
Interfaces without such an `opt` are unaffected by this change.
|
|
563
|
-
|
|
564
|
-
### A declared primitive names only itself
|
|
565
|
-
|
|
566
|
-
- **BREAKING**: the embedded generator no longer renders a use of a primitive
|
|
567
|
-
by a declaration's name. The Contract arena shares one node per structure, so
|
|
568
|
-
a name recorded for `nat64` was rendered at *every* `nat64` in the interface,
|
|
569
|
-
including ones that never wrote it. A use of a primitive — a field, an array
|
|
570
|
-
element, a variant arm, a method argument — now renders structurally
|
|
571
|
-
(`bigint`, `$.c.nat64`, and `$.Principal` for `principal`); a declaration of
|
|
572
|
-
the primitive is still emitted and exported as itself. `type Memo = nat64;
|
|
573
|
-
type R = record { a : nat64; b : Memo }` now generates `R = { a: bigint; b:
|
|
574
|
-
bigint }` where it generated `{ a: Memo; b: Memo }`, and the ICRC-1
|
|
575
|
-
ledger's `TransferArg.amount`, written `Tokens` beside `type BlockIndex =
|
|
576
|
-
nat`, is `bigint` and no longer `BlockIndex`.
|
|
577
|
-
- **BREAKING (value type)**: every `vec nat8` is `Uint8Array` / `$.c.blob()`,
|
|
578
|
-
whatever its element type is called. Before, a single `type Byte = nat8`
|
|
579
|
-
anywhere in the interface turned every `blob` and `vec Byte` into
|
|
580
|
-
`Array<Byte>`, a `number[]`. For an interface with a declared `nat8` alias
|
|
581
|
-
the generated blob types change from `number[]` to `Uint8Array`; the encoded
|
|
582
|
-
bytes do not change. The paired `@candid-core/schema` release makes
|
|
583
|
-
`schemaFromContract` load every `vec nat8` as a blob too, so a generated
|
|
584
|
-
module and a loaded schema agree.
|
|
585
|
-
- **Trade-off**: a declared alias no longer survives as the *spelling* of a
|
|
586
|
-
field's type (`amount : Tokens` reads `amount: bigint`); the type is the
|
|
587
|
-
same. Two structurally equal *record* declarations still collapse to the
|
|
588
|
-
first name, as before.
|
|
589
|
-
|
|
590
|
-
### `.did` doc comments become JSDoc
|
|
591
|
-
|
|
592
|
-
- The embedded generator writes each `.did` doc comment as JSDoc: above the
|
|
593
|
-
generated type and const of a declaration, on a record property, on a
|
|
594
|
-
variant arm's `tag`, on a method of the `Actor` type, and on the `actor`
|
|
595
|
-
export. Docs are the `///` run (or plain `//` lines) directly above the
|
|
596
|
-
item; block comments are not docs. The doc text is escaped — `*/` becomes
|
|
597
|
-
`*\/`, an `@` that could start a tag becomes `\@`, a code fence has each
|
|
598
|
-
backtick escaped — so a comment cannot end early, forge a tag or swallow the
|
|
599
|
-
generated ones.
|
|
600
|
-
- A method's `@param` tags name the `.did`'s argument names, and the `Actor`
|
|
601
|
-
method's parameters take the same names; an unnamed argument, a reserved
|
|
602
|
-
word, a name that is not identifier-shaped or a collision stays `arg{n}`.
|
|
603
|
-
- A record or union with a documented member spans several lines; without
|
|
604
|
-
docs its one-line form is unchanged. Tuple elements carry no docs.
|
|
605
|
-
- Which occurrence documents a node the arena has de-duplicated is one rule:
|
|
606
|
-
the declaration (or actor) whose structure is being emitted; occurrences
|
|
607
|
-
inside one declaration that disagree are dropped. No Contract, envelope,
|
|
608
|
-
identity or wire byte changes — docs are provenance — and the
|
|
609
|
-
`org.candid-core.field-names/v1` extension is untouched.
|
|
610
|
-
- **Additive**, with one naming change: a method written `a : (x : nat) -> ()`
|
|
611
|
-
now takes `x` as its parameter name where it took `arg0`, and gains an
|
|
612
|
-
`@param x` block, whether or not the file has a single comment. Types,
|
|
613
|
-
values and wire bytes do not move either way.
|
|
614
|
-
|
|
615
|
-
### Unrepresentable declarations are omitted, not refused
|
|
616
|
-
|
|
617
|
-
The embedded generator leaves out a declaration it cannot represent, with
|
|
618
|
-
everything that references it, instead of refusing the whole interface. One
|
|
619
|
-
exotic declaration no longer costs the module. The paired
|
|
620
|
-
`@candid-core/schema` release makes `schemaFromContract` leave out the same
|
|
621
|
-
declarations and methods, with the same reasons, so a generated module and a
|
|
622
|
-
loaded contract agree.
|
|
623
|
-
|
|
624
|
-
- **BREAKING (exit status)**: `candid-core-cli gen` used to print a
|
|
625
|
-
`ts_generation_refused` diagnostics document and exit 1 for an interface
|
|
626
|
-
with a record field or variant arm named like the `_N_` numeric-id
|
|
627
|
-
rendering (`record { _0_ : nat }`), a variant arm whose payload is a
|
|
628
|
-
declared `opt` of an uninhabited type (`type W = opt empty; type V =
|
|
629
|
-
variant { a : W }`), or a declaration named `actor` or `Actor`. It now
|
|
630
|
-
writes the module without those declarations and exits 0, printing one
|
|
631
|
-
`warning: omitted …` line per omission on stderr. A script that relied on
|
|
632
|
-
the non-zero exit to reject such an interface must read the warnings, or
|
|
633
|
-
`omitted`, instead. Stdout's report is unchanged.
|
|
634
|
-
- **BREAKING**: `didToModule` returns `{ ok: true, module, omitted }` for
|
|
635
|
-
those inputs where it returned `{ ok: false, diagnostics }`. No Candid
|
|
636
|
-
source reaches `ts_generation_refused` any more; the code stays, reserved
|
|
637
|
-
for an invalid contract graph.
|
|
638
|
-
- **The closure**: an omitted declaration takes with it every declaration
|
|
639
|
-
that references it through any edge — a field, an alias, `vec`/`opt`/record
|
|
640
|
-
nesting, a `func` type's arguments or results, a `service` type's methods —
|
|
641
|
-
up to the containing declaration. A record holding a
|
|
642
|
-
`service { f : (Bad) -> () }` is omitted whole, not stripped of `f`: a
|
|
643
|
-
service value's wire type is its full method table, and a peer would see a
|
|
644
|
-
different type. Only the actor drops individual methods, from both the
|
|
645
|
-
`actor` schema and the `Actor` type, since calling a method never encodes
|
|
646
|
-
the actor's own service type. The actor itself is never omitted, and a class
|
|
647
|
-
actor whose init arguments reference an omitted declaration keeps every
|
|
648
|
-
method (init arguments are not generated).
|
|
649
|
-
- **Everything kept is unchanged**: the modules for the other golden
|
|
650
|
-
interfaces are unchanged by omission, and a test pins that, for an interface
|
|
651
|
-
with omissions, every emitted declaration, `Actor` signature and actor
|
|
652
|
-
method is byte-identical to the module generated with the omitted
|
|
653
|
-
declarations deleted from the source.
|
|
654
|
-
- **`ModuleSuccess.omitted`** (new, always present, empty when nothing is
|
|
655
|
-
omitted): an array of `{ kind, name, reason, via? }`, declarations first,
|
|
656
|
-
then methods, each sorted by name. `kind` is `"declaration"` or
|
|
657
|
-
`"method"`. `reason` is one of `reserved_field_name`,
|
|
658
|
-
`ambiguous_variant_arm`, `reserved_export_name`, `invalid_declaration_name`
|
|
659
|
-
(Contract documents only; Candid source cannot produce one) or
|
|
660
|
-
`references_omitted`; `via` is present only for `references_omitted` and
|
|
661
|
-
names the omitted declaration referenced. This is a serialized shape: the
|
|
662
|
-
set of `reason` codes is closed, and a new code is a breaking change. The
|
|
663
|
-
type is exported by name, as `Omission`.
|
|
664
|
-
- **The module header** lists the same entries in the same order, one line
|
|
665
|
-
each, directly under the first line:
|
|
666
|
-
`// Omitted: type Holder (references_omitted via Bad)`. A module that omits
|
|
667
|
-
nothing has no such line.
|
|
668
|
-
|
|
669
|
-
### `gen` takes several entries, and gains `--json` and `--check`
|
|
670
|
-
|
|
671
|
-
- `candid-core-cli gen <a.did> [<b.did> …] [-o <dir>] [--json] [--check]`.
|
|
672
|
-
Each entry generates its own `<stem>.ts` and `<stem>.envelope.json` into the
|
|
673
|
-
one `-o` directory, byte-for-byte what a run of that entry alone writes. An
|
|
674
|
-
entry's bundle is the `.did` files beneath its own directory, with the bundle
|
|
675
|
-
limits applied per entry; entries sharing a directory share one read of it.
|
|
676
|
-
Two entries with the same stem (compared case-insensitively) are a usage
|
|
677
|
-
error (exit 64) before any work. Both rules may still change before 1.0.
|
|
678
|
-
- A failing entry no longer ends the run: every entry is attempted, and the
|
|
679
|
-
exit code is 1 if any failed, 0 otherwise. Omissions do not fail an entry.
|
|
680
|
-
For one entry the behaviour is unchanged: the same `{ ok: false,
|
|
681
|
-
diagnostics }` document on stdout and exit 1.
|
|
682
|
-
- **`--json`** prints exactly one JSON document on stdout and nothing else
|
|
683
|
-
(stderr stays empty): `{ schemaVersion, ok, check, entries, drift }`, with
|
|
684
|
-
per entry its `entry`, `status` (`written`, `unchanged`, `drifted` or
|
|
685
|
-
`failed`), `module` and `envelope` paths, `omitted`, and `diagnostics`. The
|
|
686
|
-
shape is documented in the README and typed as `CliReport` in
|
|
687
|
-
`lib/index.d.ts`; `schemaVersion` is `1`. The content-addressed identities
|
|
688
|
-
stay in the human report only.
|
|
689
|
-
- **`--check`** generates in memory, compares byte-for-byte with the files on
|
|
690
|
-
disk, writes nothing (not even the output directory) and exits 1 listing
|
|
691
|
-
each missing or drifted file; it combines with `--json` (`drift` lists the
|
|
692
|
-
paths).
|
|
693
|
-
- The CLI never reads stdin, and a test now pins that with a stdin that is an
|
|
694
|
-
open pipe nobody writes to.
|
|
695
|
-
- **Behaviour change, not breaking**: an output file that already holds the
|
|
696
|
-
generated bytes is no longer rewritten, and its line reads
|
|
697
|
-
`unchanged <path>` where it read `wrote <path>`. Bytes, names and exit codes
|
|
698
|
-
are unchanged; scripts matching `wrote ` on a re-run should match
|
|
699
|
-
`unchanged ` too, or use `--json`.
|
|
700
|
-
- Every path the CLI reports, in the document and in the human output, is the
|
|
701
|
-
entry or directory as passed (or `-o` joined with a file name), never a
|
|
702
|
-
resolved absolute path, so the same invocation prints the same bytes from any
|
|
703
|
-
working directory.
|
|
704
|
-
- The library (`didToModule`, `didToContract`, `init`) keeps its signatures;
|
|
705
|
-
`ModuleSuccess` gains `omitted` (above), and `lib/index.d.ts` adds the
|
|
706
|
-
`Omission`, `CliReport`, `CliEntryReport` and `CliEntryStatus` types.
|
|
707
|
-
|
|
708
|
-
## 0.1.0 — 2026-08-27
|
|
709
|
-
|
|
710
|
-
Embeds `candid-core` 0.1.0-beta.3 and the `candid-core-ts` generator from
|
|
711
|
-
the same repository commit the release is dispatched from; the release
|
|
712
|
-
record names the exact SHA.
|
|
713
|
-
|
|
714
|
-
The first version: the JavaScript-only on-ramp.
|
|
715
|
-
|
|
716
|
-
- **`gen <service.did> [-o <dir>]`** emits the generated
|
|
717
|
-
`@candid-core/schema` module, the one-document `ContractEnvelope` with the
|
|
718
|
-
`org.candid-core.field-names/v1` field-name table, and prints the content-addressed identities. Imports resolve
|
|
719
|
-
from the entry's directory as an in-memory bundle; every generation
|
|
720
|
-
double-runs and the tool refuses to write on any byte mismatch.
|
|
721
|
-
- **`didToContract` / `didToModule`** — the same two operations as a
|
|
722
|
-
library, for Node and browsers alike: one wasm-bindgen artifact over
|
|
723
|
-
`candid-core`'s `compiler` feature (`compile_with_resolver` +
|
|
724
|
-
`MemoryResolver`; no filesystem, no eval, no dynamic import) plus the
|
|
725
|
-
`candid-core-ts` generator. Failures are `{ ok: false, diagnostics }` with
|
|
726
|
-
the compiler's diagnostics verbatim; generator refusals surface as
|
|
727
|
-
`ts_generation_refused`, malformed requests as `invalid_request`.
|
|
728
|
-
- **Parity is a gate, not a claim**: CI compares the wasm-built outputs
|
|
729
|
-
byte-for-byte against the repository's reviewed goldens and against the
|
|
730
|
-
native `candid-core compile --envelope` fixture, builds the artifact twice
|
|
731
|
-
from clean and requires identical bytes, and runs `didToContract` inside
|
|
732
|
-
headless Chrome feeding `schemaFromContract`, envelope-carried names
|
|
733
|
-
included.
|