@matter/create 0.16.0-alpha.0-20260104-558783063 → 0.16.0-alpha.0-20260104-11833ec59

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.
@@ -1 +1 @@
1
- {"version":3,"file":"build.config.d.ts","sourceRoot":"","sources":["../../src/build.config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKxC;;GAEG;AACH,wBAAsB,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,OAAO,iBAiFxD"}
1
+ {"version":3,"file":"build.config.d.ts","sourceRoot":"","sources":["../../src/build.config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKxC;;GAEG;AACH,wBAAsB,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,OAAO,iBA2DxD"}
@@ -8,7 +8,6 @@ import { basename, dirname } from "node:path";
8
8
  async function before({ project }) {
9
9
  const createPkg = project.pkg.findPackage("@matter/create");
10
10
  await mkdir(createPkg.resolve("dist/templates"), { recursive: true });
11
- const matterJsVersion = `~${await readFile(project.pkg.workspace.resolve("version.txt"), "utf-8")}`;
12
11
  const examples = project.pkg.root.json.workspaces?.filter((ws) => ws.startsWith("examples/")) ?? [];
13
12
  if (examples.length === 0) {
14
13
  throw new Error("No examples found in workspace");
@@ -22,7 +21,6 @@ async function before({ project }) {
22
21
  if (!match) {
23
22
  continue;
24
23
  }
25
- const dependencies = {};
26
24
  const baseLength = examplesPkg.resolve(`src/`).length + 1;
27
25
  const sources = await examplesPkg.glob(`src/**/*.ts`);
28
26
  let entrypoint;
@@ -32,19 +30,6 @@ async function before({ project }) {
32
30
  entrypoint = filename;
33
31
  }
34
32
  const source = await readFile(file, "utf-8");
35
- for (const [, pkgName] of source.matchAll(/import (?:.*from )?"(@[^/"]+\/[^/"]+|[^/"]+)";/g)) {
36
- if (dependencies[pkgName]) {
37
- continue;
38
- }
39
- if (pkgName.startsWith("@matter/") || pkgName.startsWith("@project-chip/")) {
40
- dependencies[pkgName] = matterJsVersion;
41
- continue;
42
- }
43
- const version = examplesPkg.json.dependencies?.[pkgName];
44
- if (version !== void 0) {
45
- dependencies[pkgName] = version;
46
- }
47
- }
48
33
  const outFilename = createPkg.resolve("dist/templates", name, filename);
49
34
  await mkdir(dirname(outFilename), { recursive: true });
50
35
  await writeFile(outFilename, source);
@@ -54,9 +39,11 @@ async function before({ project }) {
54
39
  }
55
40
  templates.push({
56
41
  name,
57
- dependencies,
42
+ dependencies: examplesPkg.json.dependencies ?? {},
43
+ optionalDependencies: examplesPkg.json.optionalDependencies,
44
+ engines: examplesPkg.json.engines,
58
45
  description: match[1],
59
- entrypoint
46
+ entrypoint: examplesPkg.json.main ?? entrypoint
60
47
  });
61
48
  }
62
49
  const tools = project.pkg.findPackage("@matter/tools").json;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/build.config.ts"],
4
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,UAAU,eAAe;AAMlC,eAAsB,OAAO,EAAE,QAAQ,GAAoB;AACvD,QAAM,YAAY,QAAQ,IAAI,YAAY,gBAAgB;AAE1D,QAAM,MAAM,UAAU,QAAQ,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AAIpE,QAAM,kBAAkB,IAAI,MAAM,SAAS,QAAQ,IAAI,UAAU,QAAQ,aAAa,GAAG,OAAO,CAAC;AAEjG,QAAM,WAAW,QAAQ,IAAI,KAAK,KAAK,YAAY,OAAO,QAAM,GAAG,WAAW,WAAW,CAAC,KAAK,CAAC;AAChG,MAAI,SAAS,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,gCAAgC;AAAA,EACpD;AACA,QAAM,YAAY,MAAgB;AAClC,aAAW,WAAW,UAAU;AAC5B,UAAM,cAAc,QAAQ,IAAI,YAAY,WAAW,QAAQ,QAAQ,KAAK,GAAG,CAAC,EAAE;AAClF,UAAM,SAAS,YAAY,QAAQ,WAAW;AAC9C,UAAM,OAAO,SAAS,QAAQ,MAAM,CAAC;AACrC,UAAM,SAAS,MAAM,SAAS,QAAQ,OAAO,GAAG,MAAM,SAAS;AAC/D,QAAI,CAAC,OAAO;AACR;AAAA,IACJ;AAEA,UAAM,eAAe,CAAC;AAEtB,UAAM,aAAa,YAAY,QAAQ,MAAM,EAAE,SAAS;AACxD,UAAM,UAAU,MAAM,YAAY,KAAK,aAAa;AACpD,QAAI;AACJ,eAAW,QAAQ,SAAS;AACxB,YAAM,WAAW,KAAK,MAAM,UAAU;AACtC,UAAI,CAAC,cAAc,SAAS,QAAQ,GAAG,MAAM,IAAI;AAC7C,qBAAa;AAAA,MACjB;AACA,YAAM,SAAS,MAAM,SAAS,MAAM,OAAO;AAI3C,iBAAW,CAAC,EAAE,OAAO,KAAK,OAAO,SAAS,iDAAiD,GAAG;AAC1F,YAAI,aAAa,OAAO,GAAG;AACvB;AAAA,QACJ;AAEA,YAAI,QAAQ,WAAW,UAAU,KAAK,QAAQ,WAAW,gBAAgB,GAAG;AACxE,uBAAa,OAAO,IAAI;AACxB;AAAA,QACJ;AAEA,cAAM,UAAU,YAAY,KAAK,eAAe,OAAO;AACvD,YAAI,YAAY,QAAW;AACvB,uBAAa,OAAO,IAAI;AAAA,QAC5B;AAAA,MACJ;AAEA,YAAM,cAAc,UAAU,QAAQ,kBAAkB,MAAM,QAAQ;AACtE,YAAM,MAAM,QAAQ,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,YAAM,UAAU,aAAa,MAAM;AAAA,IACvC;AAEA,QAAI,CAAC,YAAY;AACb;AAAA,IACJ;AAEA,cAAU,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA,aAAa,MAAM,CAAC;AAAA,MACpB;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,QAAM,QAAQ,QAAQ,IAAI,YAAY,eAAe,EAAE;AACvD,QAAM,oBAAoB,MAAM,cAAc;AAC9C,QAAM,mBAAmB,MAAM,kBAAkB,aAAa;AAE9D,QAAM,SAAiB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,UAAU,UAAU,QAAQ,2BAA2B,GAAG,KAAK,UAAU,QAAQ,QAAW,CAAC,CAAC;AACxG;",
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,UAAU,eAAe;AAMlC,eAAsB,OAAO,EAAE,QAAQ,GAAoB;AACvD,QAAM,YAAY,QAAQ,IAAI,YAAY,gBAAgB;AAE1D,QAAM,MAAM,UAAU,QAAQ,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AAEpE,QAAM,WAAW,QAAQ,IAAI,KAAK,KAAK,YAAY,OAAO,QAAM,GAAG,WAAW,WAAW,CAAC,KAAK,CAAC;AAChG,MAAI,SAAS,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,gCAAgC;AAAA,EACpD;AACA,QAAM,YAAY,MAAgB;AAClC,aAAW,WAAW,UAAU;AAC5B,UAAM,cAAc,QAAQ,IAAI,YAAY,WAAW,QAAQ,QAAQ,KAAK,GAAG,CAAC,EAAE;AAClF,UAAM,SAAS,YAAY,QAAQ,WAAW;AAC9C,UAAM,OAAO,SAAS,QAAQ,MAAM,CAAC;AACrC,UAAM,SAAS,MAAM,SAAS,QAAQ,OAAO,GAAG,MAAM,SAAS;AAC/D,QAAI,CAAC,OAAO;AACR;AAAA,IACJ;AAEA,UAAM,aAAa,YAAY,QAAQ,MAAM,EAAE,SAAS;AACxD,UAAM,UAAU,MAAM,YAAY,KAAK,aAAa;AACpD,QAAI;AACJ,eAAW,QAAQ,SAAS;AACxB,YAAM,WAAW,KAAK,MAAM,UAAU;AACtC,UAAI,CAAC,cAAc,SAAS,QAAQ,GAAG,MAAM,IAAI;AAC7C,qBAAa;AAAA,MACjB;AACA,YAAM,SAAS,MAAM,SAAS,MAAM,OAAO;AAE3C,YAAM,cAAc,UAAU,QAAQ,kBAAkB,MAAM,QAAQ;AACtE,YAAM,MAAM,QAAQ,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,YAAM,UAAU,aAAa,MAAM;AAAA,IACvC;AAEA,QAAI,CAAC,YAAY;AACb;AAAA,IACJ;AAEA,cAAU,KAAK;AAAA,MACX;AAAA,MACA,cAAc,YAAY,KAAK,gBAAgB,CAAC;AAAA,MAChD,sBAAsB,YAAY,KAAK;AAAA,MACvC,SAAS,YAAY,KAAK;AAAA,MAC1B,aAAa,MAAM,CAAC;AAAA,MACpB,YAAY,YAAY,KAAK,QAAQ;AAAA,IACzC,CAAC;AAAA,EACL;AAEA,QAAM,QAAQ,QAAQ,IAAI,YAAY,eAAe,EAAE;AACvD,QAAM,oBAAoB,MAAM,cAAc;AAC9C,QAAM,mBAAmB,MAAM,kBAAkB,aAAa;AAE9D,QAAM,SAAiB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,UAAU,UAAU,QAAQ,2BAA2B,GAAG,KAAK,UAAU,QAAQ,QAAW,CAAC,CAAC;AACxG;",
5
5
  "names": []
6
6
  }
@@ -7,6 +7,8 @@ export declare const TEMPLATE_DIR: string;
7
7
  export interface Template {
8
8
  name: string;
9
9
  dependencies: Record<string, string>;
10
+ optionalDependencies?: Record<string, string>;
11
+ engines?: Record<string, string>;
10
12
  description: string;
11
13
  entrypoint: string;
12
14
  matterJsPackages?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,eAAO,MAAM,YAAY,QAAwC,CAAC;AAElE,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,MAAM;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACzB;AAID,wBAAsB,MAAM,oBAiB3B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,eAAO,MAAM,YAAY,QAAwC,CAAC;AAElE,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,MAAM;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACzB;AAcD,wBAAsB,MAAM,oBAgB3B"}
@@ -8,6 +8,15 @@ import { resolve } from "node:path";
8
8
  const CREATE_DIR = resolve(import.meta.dirname, "../..");
9
9
  const TEMPLATE_DIR = resolve(CREATE_DIR, "dist/templates");
10
10
  let config;
11
+ function patchVersion(version, dependencies) {
12
+ const patched = { ...dependencies };
13
+ for (const name in patched) {
14
+ if (name.startsWith("@matter/") || name.startsWith("@project-chip/")) {
15
+ patched[name] = version;
16
+ }
17
+ }
18
+ return patched;
19
+ }
11
20
  async function Config() {
12
21
  if (!config) {
13
22
  config = JSON.parse(await readFile(resolve(TEMPLATE_DIR, "index.json"), "utf-8"));
@@ -15,10 +24,9 @@ async function Config() {
15
24
  const packageJson = JSON.parse(await readFile(resolve(CREATE_DIR, "package.json"), "utf-8"));
16
25
  if (packageJson.version !== "0.0.0-git") {
17
26
  for (const template of config.templates) {
18
- for (const name in template.dependencies) {
19
- if (name.startsWith("@matter/") || name.startsWith("@project-chip/")) {
20
- template.dependencies[name] = packageJson.version;
21
- }
27
+ template.dependencies = patchVersion(packageJson.version, template.dependencies);
28
+ if (template.optionalDependencies) {
29
+ template.optionalDependencies = patchVersion(packageJson.version, template.optionalDependencies);
22
30
  }
23
31
  }
24
32
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/config.ts"],
4
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,MAAM,aAAa,QAAQ,YAAY,SAAS,OAAO;AAChD,MAAM,eAAe,QAAQ,YAAY,gBAAgB;AAgBhE,IAAI;AAEJ,eAAsB,SAAS;AAC3B,MAAI,CAAC,QAAQ;AACT,aAAS,KAAK,MAAM,MAAM,SAAS,QAAQ,cAAc,YAAY,GAAG,OAAO,CAAC;AAAA,EACpF;AAEA,QAAM,cAAc,KAAK,MAAM,MAAM,SAAS,QAAQ,YAAY,cAAc,GAAG,OAAO,CAAC;AAC3F,MAAI,YAAY,YAAY,aAAa;AACrC,eAAW,YAAY,OAAO,WAAW;AACrC,iBAAW,QAAQ,SAAS,cAAc;AACtC,YAAI,KAAK,WAAW,UAAU,KAAK,KAAK,WAAW,gBAAgB,GAAG;AAClE,mBAAS,aAAa,IAAI,IAAI,YAAY;AAAA,QAC9C;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;",
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,MAAM,aAAa,QAAQ,YAAY,SAAS,OAAO;AAChD,MAAM,eAAe,QAAQ,YAAY,gBAAgB;AAkBhE,IAAI;AAEJ,SAAS,aAAa,SAAiB,cAAsC;AACzE,QAAM,UAAkC,EAAE,GAAG,aAAa;AAC1D,aAAW,QAAQ,SAAS;AACxB,QAAI,KAAK,WAAW,UAAU,KAAK,KAAK,WAAW,gBAAgB,GAAG;AAClE,cAAQ,IAAI,IAAI;AAAA,IACpB;AAAA,EACJ;AACA,SAAO;AACX;AAEA,eAAsB,SAAS;AAC3B,MAAI,CAAC,QAAQ;AACT,aAAS,KAAK,MAAM,MAAM,SAAS,QAAQ,cAAc,YAAY,GAAG,OAAO,CAAC;AAAA,EACpF;AAEA,QAAM,cAAc,KAAK,MAAM,MAAM,SAAS,QAAQ,YAAY,cAAc,GAAG,OAAO,CAAC;AAC3F,MAAI,YAAY,YAAY,aAAa;AACrC,eAAW,YAAY,OAAO,WAAW;AACrC,eAAS,eAAe,aAAa,YAAY,SAAS,SAAS,YAAY;AAC/E,UAAI,SAAS,sBAAsB;AAC/B,iBAAS,uBAAuB,aAAa,YAAY,SAAS,SAAS,oBAAoB;AAAA,MACnG;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;",
5
5
  "names": []
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"consumer-project.d.ts","sourceRoot":"","sources":["../../src/consumer-project.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAU,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAgE7D,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,EAClC,IAAI,EACJ,IAAI,EACJ,cAAc,EACd,OAAO,GACV,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBnD;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,eAAe,iBAUhD"}
1
+ {"version":3,"file":"consumer-project.d.ts","sourceRoot":"","sources":["../../src/consumer-project.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAU,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAgE7D,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,EAClC,IAAI,EACJ,IAAI,EACJ,cAAc,EACd,OAAO,GACV,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBnD;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,eAAe,iBAUhD"}
@@ -97,7 +97,9 @@ async function createPackageJson(project) {
97
97
  const pkg = PACKAGE_JSON;
98
98
  const config = await Config();
99
99
  pkg.scripts.app = `node --enable-source-maps ${entrypointFor(project)}`;
100
+ pkg.engines = project.template.engines;
100
101
  pkg.dependencies = project.template.dependencies;
102
+ pkg.optionalDependencies = project.template.optionalDependencies;
101
103
  pkg.devDependencies["typescript"] = config.typescriptVersion;
102
104
  pkg.devDependencies["@types/node"] = config.nodeTypesVersion;
103
105
  pkg.description = project.template.description;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/consumer-project.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": ["performInstall", "template"]
6
6
  }
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @license
4
+ * Copyright 2022-2025 Matter.js Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ /**
9
+ * Shared Fabric Controller - Matter controller using external ICAC certificates.
10
+ * Demonstrates multi-controller scenarios where controllers share the same fabric
11
+ * without re-commissioning, using a 3-tier PKI hierarchy (RCAC -> ICAC -> NOC).
12
+ *
13
+ * Usage:
14
+ * npm run matter-shared-fabric toggle - Toggle the device
15
+ * npm run matter-shared-fabric on - Turn device ON
16
+ * npm run matter-shared-fabric off - Turn device OFF
17
+ * npm run matter-shared-fabric read - Read OnOff state
18
+ */
19
+
20
+ import { Bytes, Crypto, Environment, Logger, LogLevel, StorageService, Time } from "@matter/main";
21
+ import { OnOff } from "@matter/main/clusters";
22
+ import { CertificateAuthority, FabricBuilder, Rcac } from "@matter/main/protocol";
23
+ import { EndpointNumber, FabricId, FabricIndex, NodeId, VendorId } from "@matter/main/types";
24
+ import { CommissioningController } from "@project-chip/matter.js";
25
+ import * as fs from "fs";
26
+ import * as path from "path";
27
+
28
+ const logger = Logger.get("SharedFabricController");
29
+
30
+ // Suppress unhandled rejections during shutdown (expected when closing connections)
31
+ let shuttingDown = false;
32
+ process.on("unhandledRejection", (reason: unknown) => {
33
+ if (shuttingDown) {
34
+ // Expected during shutdown - peer closed, end of stream, etc.
35
+ return;
36
+ }
37
+ console.error("Unhandled rejection:", reason);
38
+ });
39
+
40
+ // Get command from args
41
+ const command = process.argv[2]?.toLowerCase();
42
+
43
+ if (!command || !["toggle", "on", "off", "read"].includes(command)) {
44
+ console.log(`
45
+ Shared Fabric Controller - External ICAC Certificate Example
46
+
47
+ This controller uses external certificates (RCAC + ICAC) to join an existing
48
+ fabric without re-commissioning. Demonstrates multi-controller scenarios where
49
+ multiple controllers share the same fabric using a 3-tier PKI hierarchy.
50
+
51
+ Usage:
52
+ npm run matter-shared-fabric toggle - Toggle the device ON/OFF
53
+ npm run matter-shared-fabric on - Turn device ON
54
+ npm run matter-shared-fabric off - Turn device OFF
55
+ npm run matter-shared-fabric read - Read current OnOff state
56
+
57
+ Environment Variables:
58
+ MATTER_CERTDIR - Certificate directory (required, default: ./certificates)
59
+ Must contain: rcac.chip, icac.chip, icac_key.bin
60
+ MATTER_FABRICID - Fabric ID (default: 1)
61
+ MATTER_NODEID - This controller's Node ID (default: 200)
62
+ MATTER_TARGETNODEID - Target device Node ID (default: 1)
63
+ MATTER_ENDPOINT - Target endpoint (default: 1)
64
+
65
+ Certificate Requirements:
66
+ - rcac.chip : Root CA certificate in Matter TLV format
67
+ - icac.chip : Intermediate CA certificate in Matter TLV format
68
+ - icac_key.bin : Intermediate CA private key in chip-tool binary format
69
+
70
+ See README.md for detailed setup instructions.
71
+ `);
72
+ process.exit(1);
73
+ }
74
+
75
+ const environment = Environment.default;
76
+ const storageService = environment.get(StorageService);
77
+
78
+ function parseChipKeyBinary(keyPath: string): { publicKey: Bytes; privateKey: Bytes } {
79
+ const keyBuffer = fs.readFileSync(keyPath);
80
+ const keyBytes = Bytes.of(new Uint8Array(keyBuffer));
81
+ if (keyBytes.length !== 97 || keyBytes[0] !== 4) {
82
+ throw new Error(`Invalid chip-tool key format`);
83
+ }
84
+ return {
85
+ publicKey: Bytes.of(keyBytes.slice(0, 65)),
86
+ privateKey: Bytes.of(keyBytes.slice(65, 97)),
87
+ };
88
+ }
89
+
90
+ function loadTlvCertificate(certPath: string): Bytes {
91
+ return Bytes.of(new Uint8Array(fs.readFileSync(certPath)));
92
+ }
93
+
94
+ async function computeKeyIdentifier(publicKey: Bytes): Promise<Bytes> {
95
+ const nodeCrypto = await import("crypto");
96
+ const publicKeyBuffer = Buffer.from(Bytes.of(publicKey));
97
+ const sha256 = nodeCrypto.createHash("sha256").update(publicKeyBuffer).digest();
98
+ return Bytes.of(new Uint8Array(sha256));
99
+ }
100
+
101
+ function getDefaultChipToolIpk(): Bytes {
102
+ return Bytes.of(new Uint8Array(Buffer.from("temporary ipk 01", "ascii")));
103
+ }
104
+
105
+ async function main() {
106
+ const certDir = process.env.MATTER_CERTDIR ?? "./certificates";
107
+ const fabricId = BigInt(process.env.MATTER_FABRICID ?? "1");
108
+ const nodeId = Number(process.env.MATTER_NODEID ?? "200");
109
+ const targetDeviceNodeId = Number(process.env.MATTER_TARGETNODEID ?? "1");
110
+ const targetEndpoint = Number(process.env.MATTER_ENDPOINT ?? "1");
111
+
112
+ // Certificate paths - Note: RCAC private key is NOT required when using ICAC
113
+ // Only need: RCAC cert (public), ICAC cert, ICAC private key
114
+ const rcacCertPath = path.join(certDir, "rcac.chip");
115
+ const icacCertPath = path.join(certDir, "icac.chip");
116
+ const icacKeyPath = path.join(certDir, "icac_key.bin");
117
+
118
+ // Verify files exist
119
+ for (const [name, filePath] of [
120
+ ["RCAC certificate", rcacCertPath],
121
+ ["ICAC certificate", icacCertPath],
122
+ ["ICAC key", icacKeyPath],
123
+ ] as const) {
124
+ if (!fs.existsSync(filePath)) {
125
+ console.error(`Error: ${name} not found at ${filePath}`);
126
+ process.exit(1);
127
+ }
128
+ }
129
+
130
+ // Load certificates
131
+ const rcacCertBytes = loadTlvCertificate(rcacCertPath);
132
+ const icacCertBytes = loadTlvCertificate(icacCertPath);
133
+ const icacKeyPair = parseChipKeyBinary(icacKeyPath);
134
+
135
+ // Parse RCAC certificate to extract public key (no private key needed!)
136
+ const rcacCert = Rcac.fromTlv(rcacCertBytes);
137
+ const rcacPublicKey = Bytes.of(rcacCert.cert.ellipticCurvePublicKey);
138
+
139
+ const ipk = getDefaultChipToolIpk();
140
+ const crypto = environment.get(Crypto);
141
+
142
+ // Compute key identifiers from public keys
143
+ const rcacKeyIdentifier = await computeKeyIdentifier(rcacPublicKey);
144
+ const icacKeyIdentifier = await computeKeyIdentifier(icacKeyPair.publicKey);
145
+
146
+ // Create Certificate Authority - NO RCAC private key needed when using ICAC!
147
+ // The ICAC key will be used to sign NOCs
148
+ const certificateAuthority = await CertificateAuthority.create(crypto, {
149
+ rootCertId: BigInt("0xCACACACA00000001"),
150
+ // rootKeyPair is NOT provided - we don't have/need the RCAC private key
151
+ rootKeyIdentifier: rcacKeyIdentifier,
152
+ rootCertBytes: rcacCertBytes,
153
+ nextCertificateId: BigInt(3),
154
+ icacCertId: BigInt("0xCACACACA00000102"),
155
+ icacKeyPair: { publicKey: icacKeyPair.publicKey, privateKey: icacKeyPair.privateKey },
156
+ icacKeyIdentifier,
157
+ icacCertBytes,
158
+ });
159
+
160
+ // Build fabric
161
+ const fabricBuilder = await FabricBuilder.create(crypto);
162
+ await fabricBuilder.setRootCert(certificateAuthority.rootCert);
163
+ fabricBuilder
164
+ .setRootNodeId(NodeId(BigInt(nodeId)))
165
+ .setIdentityProtectionKey(ipk)
166
+ .setRootVendorId(VendorId(65521))
167
+ .setLabel("Matter.js Controller");
168
+
169
+ const noc = await certificateAuthority.generateNoc(
170
+ fabricBuilder.publicKey,
171
+ FabricId(fabricId),
172
+ NodeId(BigInt(nodeId)),
173
+ );
174
+ await fabricBuilder.setOperationalCert(noc, certificateAuthority.icacCert);
175
+ const fabric = await fabricBuilder.build(FabricIndex(1));
176
+
177
+ // Get controller storage
178
+ const controllerStorage = (await storageService.open("shared-fabric-controller")).createContext("data");
179
+ const uniqueId = (await controllerStorage.has("uniqueid"))
180
+ ? await controllerStorage.get<string>("uniqueid")
181
+ : `shared-fabric-controller-${Time.nowMs.toString()}`;
182
+ await controllerStorage.set("uniqueid", uniqueId);
183
+
184
+ // Create CommissioningController with our pre-built fabric
185
+ const commissioningController = new CommissioningController({
186
+ environment: {
187
+ environment,
188
+ id: uniqueId,
189
+ },
190
+ autoConnect: false,
191
+ adminFabricLabel: "Matter.js Controller",
192
+ adminFabricId: FabricId(fabricId),
193
+ rootNodeId: NodeId(BigInt(nodeId)),
194
+ adminVendorId: VendorId(65521),
195
+ rootCertificateAuthority: certificateAuthority,
196
+ rootFabric: fabric,
197
+ });
198
+
199
+ await commissioningController.start();
200
+
201
+ let node;
202
+ try {
203
+ logger.info(`Connecting to device (Node ID: ${targetDeviceNodeId})...`);
204
+
205
+ node = await commissioningController.getNode(NodeId(targetDeviceNodeId), true);
206
+ node.connect();
207
+
208
+ if (!node.initialized) {
209
+ await node.events.initialized;
210
+ }
211
+
212
+ // Get OnOff cluster client using low-level API
213
+ const onOffCluster = node.getClusterClientForDevice(EndpointNumber(targetEndpoint), OnOff.Complete);
214
+ if (!onOffCluster) {
215
+ console.error(`Error: OnOff cluster not found on endpoint ${targetEndpoint}`);
216
+ shuttingDown = true;
217
+ await commissioningController.close().catch(() => {});
218
+ process.exit(1);
219
+ }
220
+
221
+ logger.info(`Found OnOff cluster on endpoint ${targetEndpoint}`);
222
+
223
+ // Execute command
224
+ switch (command) {
225
+ case "toggle":
226
+ await onOffCluster.toggle();
227
+ const stateAfterToggle = await onOffCluster.getOnOffAttribute();
228
+ console.log(`Toggled! OnOff is now: ${stateAfterToggle ? "ON" : "OFF"}`);
229
+ break;
230
+ case "on":
231
+ await onOffCluster.on();
232
+ console.log("Device turned ON");
233
+ break;
234
+ case "off":
235
+ await onOffCluster.off();
236
+ console.log("Device turned OFF");
237
+ break;
238
+ case "read":
239
+ const currentState = await onOffCluster.getOnOffAttribute();
240
+ console.log(`OnOff state: ${currentState ? "ON" : "OFF"}`);
241
+ break;
242
+ }
243
+
244
+ console.log("Done!");
245
+ } catch (error) {
246
+ console.error(`Error: ${error}`);
247
+ shuttingDown = true;
248
+ Logger.level = LogLevel.FATAL; // Suppress INFO/WARN logs during shutdown
249
+ await commissioningController.close().catch(() => {});
250
+ process.exit(1);
251
+ }
252
+
253
+ // Clean shutdown - suppress logs and disconnect node first, then close controller
254
+ shuttingDown = true;
255
+ Logger.level = LogLevel.FATAL; // Suppress INFO/WARN logs during shutdown
256
+ if (node) {
257
+ await node.disconnect().catch(() => {});
258
+ }
259
+ await commissioningController.close().catch(() => {});
260
+ process.exit(0);
261
+ }
262
+
263
+ main().catch(error => {
264
+ console.error(`Fatal error: ${error}`);
265
+ process.exit(1);
266
+ });
@@ -5,144 +5,211 @@
5
5
  {
6
6
  "name": "examples-control-onoff",
7
7
  "dependencies": {
8
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
8
+ "@matter/main": "*"
9
+ },
10
+ "engines": {
11
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
9
12
  },
10
13
  "description": "Simple light controller",
11
- "entrypoint": "OnOffController.ts"
14
+ "entrypoint": "src/OnOffController.ts"
12
15
  },
13
16
  {
14
17
  "name": "examples-controller",
15
18
  "dependencies": {
16
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063",
17
- "@project-chip/matter.js": "~0.16.0-alpha.0-20260104-558783063",
18
- "@matter/nodejs-ble": "~0.16.0-alpha.0-20260104-558783063"
19
+ "@matter/main": "*",
20
+ "@project-chip/matter.js": "*"
21
+ },
22
+ "optionalDependencies": {
23
+ "@matter/nodejs-ble": "*"
24
+ },
25
+ "engines": {
26
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
19
27
  },
20
28
  "description": "Controller example to commission and connect devices",
21
- "entrypoint": "ControllerNode.ts"
29
+ "entrypoint": "src/ControllerNode.ts"
30
+ },
31
+ {
32
+ "name": "examples-controller-shared-fabric",
33
+ "dependencies": {
34
+ "@matter/main": "*",
35
+ "@project-chip/matter.js": "*"
36
+ },
37
+ "engines": {
38
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
39
+ },
40
+ "description": "Multi-Controller with External Certificates",
41
+ "entrypoint": "SharedFabricController.ts"
22
42
  },
23
43
  {
24
44
  "name": "examples-device-air-quality-sensor",
25
45
  "dependencies": {
26
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
46
+ "@matter/main": "*"
47
+ },
48
+ "engines": {
49
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
27
50
  },
28
51
  "description": "Air quality sensor example",
29
- "entrypoint": "AirQualitySensorDeviceNode.ts"
52
+ "entrypoint": "src/AirQualitySensorDeviceNode.ts"
30
53
  },
31
54
  {
32
55
  "name": "examples-device-bridge-onoff",
33
56
  "dependencies": {
34
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
57
+ "@matter/main": "*"
58
+ },
59
+ "engines": {
60
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
35
61
  },
36
62
  "description": "Bridge for multiple OnOff light/sockets with a CLI command execution interface",
37
- "entrypoint": "BridgedDevicesNode.ts"
63
+ "entrypoint": "src/BridgedDevicesNode.ts"
38
64
  },
39
65
  {
40
66
  "name": "examples-device-composed-onoff",
41
67
  "dependencies": {
42
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
68
+ "@matter/main": "*"
69
+ },
70
+ "engines": {
71
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
43
72
  },
44
73
  "description": "Composed device for multiple OnOff light/sockets with a CLI command execution interface",
45
- "entrypoint": "ComposedDeviceNode.ts"
74
+ "entrypoint": "src/ComposedDeviceNode.ts"
46
75
  },
47
76
  {
48
77
  "name": "examples-device-composed-wc-light",
49
78
  "dependencies": {
50
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
79
+ "@matter/main": "*"
80
+ },
81
+ "engines": {
82
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
51
83
  },
52
84
  "description": "Composed device with Window covering and a light endpoint that logs changes",
53
- "entrypoint": "IlluminatedRollerShade.ts"
85
+ "entrypoint": "src/IlluminatedRollerShade.ts"
54
86
  },
55
87
  {
56
88
  "name": "examples-device-measuring-socket",
57
89
  "dependencies": {
58
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
90
+ "@matter/main": "*"
91
+ },
92
+ "engines": {
93
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
59
94
  },
60
95
  "description": "Socket device that reports random Energy and Power measurements",
61
- "entrypoint": "MeasuredSocketDevice.ts"
96
+ "entrypoint": "src/MeasuredSocketDevice.ts"
62
97
  },
63
98
  {
64
99
  "name": "examples-device-multiple-onoff",
65
100
  "dependencies": {
66
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
101
+ "@matter/main": "*"
102
+ },
103
+ "engines": {
104
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
67
105
  },
68
106
  "description": "Multiple OnOff light/socket nodes in one process with a CLI command execution interface",
69
- "entrypoint": "MultiDeviceNode.ts"
107
+ "entrypoint": "src/MultiDeviceNode.ts"
70
108
  },
71
109
  {
72
110
  "name": "examples-device-onoff",
73
111
  "dependencies": {
74
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
112
+ "@matter/main": "*"
113
+ },
114
+ "engines": {
115
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
75
116
  },
76
117
  "description": "OnOff light/socket device with a CLI command execution interface",
77
- "entrypoint": "DeviceNode.ts"
118
+ "entrypoint": "src/DeviceNode.ts"
78
119
  },
79
120
  {
80
121
  "name": "examples-device-onoff-advanced",
81
122
  "dependencies": {
82
- "@matter/nodejs": "~0.16.0-alpha.0-20260104-558783063",
83
- "@matter/nodejs-ble": "~0.16.0-alpha.0-20260104-558783063",
84
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
123
+ "@matter/main": "*",
124
+ "@matter/nodejs": "*"
125
+ },
126
+ "optionalDependencies": {
127
+ "@matter/nodejs-ble": "*"
128
+ },
129
+ "engines": {
130
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
85
131
  },
86
132
  "description": "OnOff light/socket device with BLE support and advanced API usage",
87
- "entrypoint": "DeviceNodeFull.ts"
133
+ "entrypoint": "src/DeviceNodeFull.ts"
88
134
  },
89
135
  {
90
136
  "name": "examples-device-onoff-light",
91
137
  "dependencies": {
92
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
138
+ "@matter/main": "*"
139
+ },
140
+ "engines": {
141
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
93
142
  },
94
143
  "description": "OnOff light example which logs the state changes to the console",
95
- "entrypoint": "LightDevice.ts"
144
+ "entrypoint": "src/LightDevice.ts"
96
145
  },
97
146
  {
98
147
  "name": "examples-device-robotic-vacuum-cleaner",
99
148
  "dependencies": {
100
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
149
+ "@matter/main": "*"
150
+ },
151
+ "engines": {
152
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
101
153
  },
102
154
  "description": "Robotic Vacuum Cleaner Example",
103
- "entrypoint": "RoboticVacuumCleanerDevice.ts"
155
+ "entrypoint": "src/RoboticVacuumCleanerDevice.ts"
104
156
  },
105
157
  {
106
158
  "name": "examples-device-sensor",
107
159
  "dependencies": {
108
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
160
+ "@matter/main": "*"
161
+ },
162
+ "engines": {
163
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
109
164
  },
110
165
  "description": "Temperature/Humidity sensor with a CLI command interface to get the value",
111
- "entrypoint": "SensorDeviceNode.ts"
166
+ "entrypoint": "src/SensorDeviceNode.ts"
112
167
  },
113
168
  {
114
169
  "name": "examples-device-simple",
115
170
  "dependencies": {
116
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
171
+ "@matter/main": "*"
172
+ },
173
+ "engines": {
174
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
117
175
  },
118
176
  "description": "A simple on/off device",
119
- "entrypoint": "main.ts"
177
+ "entrypoint": "src/main.ts"
120
178
  },
121
179
  {
122
180
  "name": "examples-device-smoke-co-alarm",
123
181
  "dependencies": {
124
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063"
182
+ "@matter/main": "*"
183
+ },
184
+ "engines": {
185
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
125
186
  },
126
187
  "description": "Smoke CO Alarm Example",
127
- "entrypoint": "SmokeCOAlarmDeviceNode.ts"
188
+ "entrypoint": "src/SmokeCOAlarmDeviceNode.ts"
128
189
  },
129
190
  {
130
191
  "name": "examples-mqtt-device",
131
192
  "dependencies": {
132
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063",
133
- "@matter/mqtt": "~0.16.0-alpha.0-20260104-558783063"
193
+ "@matter/main": "*",
194
+ "@matter/mqtt": "*"
195
+ },
196
+ "engines": {
197
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
134
198
  },
135
199
  "description": "Example device with MQTT control enabled",
136
- "entrypoint": "MqttDevice.ts"
200
+ "entrypoint": "src/MqttDevice.ts"
137
201
  },
138
202
  {
139
203
  "name": "examples-web-socket-device",
140
204
  "dependencies": {
141
- "@matter/main": "~0.16.0-alpha.0-20260104-558783063",
142
- "@matter/nodejs-ws": "~0.16.0-alpha.0-20260104-558783063"
205
+ "@matter/main": "*",
206
+ "@matter/nodejs-ws": "*"
207
+ },
208
+ "engines": {
209
+ "node": ">=20.19.0 <22.0.0 || >=22.13.0"
143
210
  },
144
211
  "description": "Example device with WebSocket control enabled",
145
- "entrypoint": "WebSocketDevice.ts"
212
+ "entrypoint": "src/WebSocketDevice.ts"
146
213
  }
147
214
  ]
148
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matter/create",
3
- "version": "0.16.0-alpha.0-20260104-558783063",
3
+ "version": "0.16.0-alpha.0-20260104-11833ec59",
4
4
  "description": "Matter.js skeleton project generator",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "homepage": "https://github.com/matter-js/matter.js#readme",
34
34
  "devDependencies": {
35
- "@matter/tools": "0.16.0-alpha.0-20260104-558783063",
35
+ "@matter/tools": "0.16.0-alpha.0-20260104-11833ec59",
36
36
  "@types/node": "^25.0.2",
37
37
  "@types/tar-stream": "^3.1.4"
38
38
  },
@@ -17,10 +17,6 @@ export async function before({ project }: Project.Context) {
17
17
 
18
18
  await mkdir(createPkg.resolve("dist/templates"), { recursive: true });
19
19
 
20
- // We set the version after build so we don't know actual version here. This placeholder is just used in dev. We
21
- // then replace with the "create" package version on init if it's not a git build
22
- const matterJsVersion = `~${await readFile(project.pkg.workspace.resolve("version.txt"), "utf-8")}`;
23
-
24
20
  const examples = project.pkg.root.json.workspaces?.filter(ws => ws.startsWith("examples/")) ?? [];
25
21
  if (examples.length === 0) {
26
22
  throw new Error("No examples found in workspace");
@@ -35,8 +31,6 @@ export async function before({ project }: Project.Context) {
35
31
  continue;
36
32
  }
37
33
 
38
- const dependencies = {} as Record<string, string>;
39
-
40
34
  const baseLength = examplesPkg.resolve(`src/`).length + 1;
41
35
  const sources = await examplesPkg.glob(`src/**/*.ts`);
42
36
  let entrypoint;
@@ -47,24 +41,6 @@ export async function before({ project }: Project.Context) {
47
41
  }
48
42
  const source = await readFile(file, "utf-8");
49
43
 
50
- // Quick hack to pull out imports, assumes modules formatted by prettier. More than sufficient for current
51
- // needs
52
- for (const [, pkgName] of source.matchAll(/import (?:.*from )?"(@[^/"]+\/[^/"]+|[^/"]+)";/g)) {
53
- if (dependencies[pkgName]) {
54
- continue;
55
- }
56
-
57
- if (pkgName.startsWith("@matter/") || pkgName.startsWith("@project-chip/")) {
58
- dependencies[pkgName] = matterJsVersion;
59
- continue;
60
- }
61
-
62
- const version = examplesPkg.json.dependencies?.[pkgName];
63
- if (version !== undefined) {
64
- dependencies[pkgName] = version;
65
- }
66
- }
67
-
68
44
  const outFilename = createPkg.resolve("dist/templates", name, filename);
69
45
  await mkdir(dirname(outFilename), { recursive: true });
70
46
  await writeFile(outFilename, source);
@@ -76,9 +52,11 @@ export async function before({ project }: Project.Context) {
76
52
 
77
53
  templates.push({
78
54
  name,
79
- dependencies,
55
+ dependencies: examplesPkg.json.dependencies ?? {},
56
+ optionalDependencies: examplesPkg.json.optionalDependencies,
57
+ engines: examplesPkg.json.engines,
80
58
  description: match[1],
81
- entrypoint,
59
+ entrypoint: examplesPkg.json.main ?? entrypoint,
82
60
  });
83
61
  }
84
62
 
package/src/config.ts CHANGED
@@ -13,6 +13,8 @@ export const TEMPLATE_DIR = resolve(CREATE_DIR, "dist/templates");
13
13
  export interface Template {
14
14
  name: string;
15
15
  dependencies: Record<string, string>;
16
+ optionalDependencies?: Record<string, string>;
17
+ engines?: Record<string, string>;
16
18
  description: string;
17
19
  entrypoint: string;
18
20
  matterJsPackages?: string[];
@@ -26,6 +28,16 @@ export interface Config {
26
28
 
27
29
  let config: Config | undefined;
28
30
 
31
+ function patchVersion(version: string, dependencies: Record<string, string>) {
32
+ const patched: Record<string, string> = { ...dependencies };
33
+ for (const name in patched) {
34
+ if (name.startsWith("@matter/") || name.startsWith("@project-chip/")) {
35
+ patched[name] = version;
36
+ }
37
+ }
38
+ return patched;
39
+ }
40
+
29
41
  export async function Config() {
30
42
  if (!config) {
31
43
  config = JSON.parse(await readFile(resolve(TEMPLATE_DIR, "index.json"), "utf-8")) as Config;
@@ -34,10 +46,9 @@ export async function Config() {
34
46
  const packageJson = JSON.parse(await readFile(resolve(CREATE_DIR, "package.json"), "utf-8")) as { version: string };
35
47
  if (packageJson.version !== "0.0.0-git") {
36
48
  for (const template of config.templates) {
37
- for (const name in template.dependencies) {
38
- if (name.startsWith("@matter/") || name.startsWith("@project-chip/")) {
39
- template.dependencies[name] = packageJson.version;
40
- }
49
+ template.dependencies = patchVersion(packageJson.version, template.dependencies);
50
+ if (template.optionalDependencies) {
51
+ template.optionalDependencies = patchVersion(packageJson.version, template.optionalDependencies);
41
52
  }
42
53
  }
43
54
  }
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import type { PackageJson } from "@matter/tools";
7
8
  import { execSync } from "node:child_process";
8
9
  import { cp, mkdir, writeFile } from "node:fs/promises";
9
10
  import { basename, resolve } from "node:path";
@@ -13,7 +14,7 @@ import { bold } from "./formatting.js";
13
14
  import { notice } from "./messages.js";
14
15
  import { createAndValidateDest, install, ProjectError, TemplateNotFoundError } from "./new-project.js";
15
16
 
16
- const PACKAGE_JSON = {
17
+ const PACKAGE_JSON: PackageJson = {
17
18
  dependencies: {} as Record<string, string>,
18
19
  devDependencies: {
19
20
  typescript: "*",
@@ -130,13 +131,15 @@ async function createPackageJson(project: ConsumerProject) {
130
131
 
131
132
  const config = await Config();
132
133
 
133
- pkg.scripts.app = `node --enable-source-maps ${entrypointFor(project)}`;
134
+ pkg.scripts!.app = `node --enable-source-maps ${entrypointFor(project)}`;
134
135
 
136
+ pkg.engines = project.template.engines;
135
137
  pkg.dependencies = project.template.dependencies;
136
- pkg.devDependencies["typescript"] = config.typescriptVersion;
137
- pkg.devDependencies["@types/node"] = config.nodeTypesVersion;
138
+ pkg.optionalDependencies = project.template.optionalDependencies;
139
+ pkg.devDependencies!["typescript"] = config.typescriptVersion;
140
+ pkg.devDependencies!["@types/node"] = config.nodeTypesVersion;
138
141
 
139
- (pkg as any).description = project.template.description;
142
+ pkg.description = project.template.description;
140
143
 
141
144
  let author, authorEmail;
142
145
  try {