Skip to content

Commit

Permalink
Merge branch 'main' into kumpis/add-explorer-templates
Browse files Browse the repository at this point in the history
  • Loading branch information
karooolis authored Aug 23, 2024
2 parents 1a0b852 + 04c675c commit ff31dfa
Show file tree
Hide file tree
Showing 19 changed files with 346 additions and 68 deletions.
6 changes: 6 additions & 0 deletions .changeset/quick-frogs-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@latticexyz/config": patch
"@latticexyz/store": patch
---

Fixed a few type issues with `namespaceLabel` in tables and added/clarified TSDoc for config input/output objects.
7 changes: 7 additions & 0 deletions .changeset/tasty-toys-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@latticexyz/cli": patch
"@latticexyz/world": patch
---

Add a strongly typed `namespaceLabel` to the system config output.
It corresponds to the `label` of the namespace the system belongs to and can't be set manually.
7 changes: 6 additions & 1 deletion packages/cli/src/deploy/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,24 @@ export type Library = DeterministicContract & {
};

export type System = DeterministicContract & {
// labels
readonly label: string;
readonly namespaceLabel: string;
// resource ID
readonly namespace: string;
readonly name: string;
readonly systemId: Hex;
// access
readonly allowAll: boolean;
readonly allowedAddresses: readonly Hex[];
readonly allowedSystemIds: readonly Hex[];
// world registration
readonly worldFunctions: readonly WorldFunction[];
};

export type DeployedSystem = Omit<
System,
"label" | "abi" | "prepareDeploy" | "deployedBytecodeSize" | "allowedSystemIds"
"label" | "namespaceLabel" | "abi" | "prepareDeploy" | "deployedBytecodeSize" | "allowedSystemIds"
> & {
address: Address;
};
Expand Down
28 changes: 27 additions & 1 deletion packages/config/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,39 @@ export type Schema = {
};

export type Table = {
/**
* Human-readable label for this table. Used as config keys, library names, and filenames.
* Labels are not length constrained like resource names, but special characters should be avoided to be compatible with the filesystem, Solidity compiler, etc.
*/
readonly label: string;
/**
* Human-readable label for this table's namespace. Used for namespace config keys and directory names.
*/
readonly namespaceLabel: string;
/**
* Table type used in table's resource ID and determines how storage and events are used by this table.
*/
readonly type: satisfy<ResourceType, "table" | "offchainTable">;
/**
* Table namespace used in table's resource ID and determines access control.
*/
readonly namespace: string;
readonly namespaceLabel: string;
/**
* Table name used in table's resource ID.
*/
readonly name: string;
/**
* Table's resource ID.
*/
readonly tableId: Hex;
/**
* Schema definition for this table's records.
*/
readonly schema: Schema;
/**
* Primary key for records of this table. An array of zero or more schema field names.
* Using an empty array acts like a singleton, where only one record can exist for this table.
*/
readonly key: readonly string[];
};

Expand Down
4 changes: 2 additions & 2 deletions packages/store/ts/config/v2/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export const TABLE_DEPLOY_DEFAULTS = {
export type TABLE_DEPLOY_DEFAULTS = typeof TABLE_DEPLOY_DEFAULTS;

export const TABLE_DEFAULTS = {
namespace: "",
namespaceLabel: "",
type: "table",
} as const satisfies Pick<TableInput, "namespace" | "type">;
} as const satisfies Pick<TableInput, "namespaceLabel" | "type">;

export type TABLE_DEFAULTS = typeof TABLE_DEFAULTS;

Expand Down
22 changes: 15 additions & 7 deletions packages/store/ts/config/v2/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ export type TableDeployInput = Partial<TableDeploy>;

export type TableInput = {
/**
* Human-readable table label. Used as config keys, table library names, and filenames.
* Human-readable label for this table. Used as config keys, library names, and filenames.
* Labels are not length constrained like resource names, but special characters should be avoided to be compatible with the filesystem, Solidity compiler, etc.
*/
readonly label: string;
/**
* Human-readable label for this table's namespace. Used for namespace config keys and directory names.
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespaceLabel?: string;
/**
* Table type used in table's resource ID and determines how storage and events are used by this table.
* Defaults to `table` if not set.
*/
readonly type?: "table" | "offchainTable";
Expand All @@ -31,17 +37,19 @@ export type TableInput = {
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespace?: string;
/**
* Human-readable namespace label.
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespaceLabel?: string;
/**
* Table name used in table's resource ID.
* Defaults to the first 16 characters of `label` if not set.
*/
readonly name?: string;
/**
* Schema definition for this table's records.
*/
readonly schema: SchemaInput;
/**
* Primary key for records of this table. An array of zero or more schema field names.
* Using an empty array acts like a singleton, where only one record can exist for this table.
*/
readonly key: readonly string[];
readonly codegen?: TableCodegenInput;
readonly deploy?: TableDeployInput;
Expand All @@ -52,7 +60,7 @@ export type TableShorthandInput = SchemaInput | string;
export type TablesInput = {
// remove label and namespace as these are set contextually
// and allow defining a table using shorthand
readonly [label: string]: Omit<TableInput, "label" | "namespace" | "namespaceLabel"> | TableShorthandInput;
readonly [label: string]: Omit<TableInput, "label" | "namespaceLabel" | "namespace"> | TableShorthandInput;
};

export type CodegenInput = Partial<Codegen>;
Expand Down
67 changes: 55 additions & 12 deletions packages/store/ts/config/v2/store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ describe("defineStore", () => {
readonly tables: {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly type: "table"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -115,8 +115,8 @@ describe("defineStore", () => {
readonly tables: {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly type: "table"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -237,8 +237,8 @@ describe("defineStore", () => {
readonly tables: {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly type: "table"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -271,8 +271,8 @@ describe("defineStore", () => {
readonly tables: {
readonly root__Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly type: "table"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -651,36 +651,56 @@ describe("defineStore", () => {
namespace: "CustomNS",
tables: {
Example: {
// @ts-expect-error "Overrides of `label` and `namespace` are not allowed for tables in this context"
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
label: "NotAllowed",
schema: { id: "address" },
key: ["id"],
},
},
}),
).throwsAndHasTypeError("Overrides of `label` and `namespace` are not allowed for tables in this context");
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);

attest(() =>
defineStore({
namespace: "CustomNS",
tables: {
Example: {
// @ts-expect-error "Overrides of `label` and `namespace` are not allowed for tables in this context"
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
namespaceLabel: "NotAllowed",
schema: { id: "address" },
key: ["id"],
},
},
}),
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);

attest(() =>
defineStore({
namespace: "CustomNS",
tables: {
Example: {
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
namespace: "NotAllowed",
schema: { id: "address" },
key: ["id"],
},
},
}),
).throwsAndHasTypeError("Overrides of `label` and `namespace` are not allowed for tables in this context");
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);

attest(() =>
defineStore({
namespaces: {
CustomNS: {
tables: {
Example: {
// @ts-expect-error "Overrides of `label` and `namespace` are not allowed for tables in this context"
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
label: "NotAllowed",
schema: { id: "address" },
key: ["id"],
Expand All @@ -689,15 +709,36 @@ describe("defineStore", () => {
},
},
}),
).throwsAndHasTypeError("Overrides of `label` and `namespace` are not allowed for tables in this context");
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);

attest(() =>
defineStore({
namespaces: {
CustomNS: {
tables: {
Example: {
// @ts-expect-error "Overrides of `label` and `namespace` are not allowed for tables in this context"
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
namespaceLabel: "NotAllowed",
schema: { id: "address" },
key: ["id"],
},
},
},
},
}),
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);

attest(() =>
defineStore({
namespaces: {
CustomNS: {
tables: {
Example: {
// @ts-expect-error "Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"
namespace: "NotAllowed",
schema: { id: "address" },
key: ["id"],
Expand All @@ -706,7 +747,9 @@ describe("defineStore", () => {
},
},
}),
).throwsAndHasTypeError("Overrides of `label` and `namespace` are not allowed for tables in this context");
).throwsAndHasTypeError(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context",
);
});

it("should allow const enum as input", () => {
Expand Down
23 changes: 15 additions & 8 deletions packages/store/ts/config/v2/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export type ValidateTableOptions = { inStoreContext: boolean };

export type requiredTableKey<inStoreContext extends boolean> = Exclude<
requiredKeyOf<TableInput>,
inStoreContext extends true ? "label" | "namespace" : ""
inStoreContext extends true ? "label" | "namespaceLabel" | "namespace" : never
>;

export type validateTable<
Expand All @@ -59,9 +59,9 @@ export type validateTable<
? validateKeys<getStaticAbiTypeKeys<conform<get<input, "schema">, SchemaInput>, scope>, get<input, key>>
: key extends "schema"
? validateSchema<get<input, key>, scope>
: key extends "label" | "namespace"
: key extends "label" | "namespaceLabel" | "namespace"
? options["inStoreContext"] extends true
? ErrorMessage<"Overrides of `label` and `namespace` are not allowed for tables in this context">
? ErrorMessage<"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context">
: key extends keyof input
? narrow<input[key]>
: never
Expand Down Expand Up @@ -115,8 +115,13 @@ export function validateTable<input, scope extends Scope = AbiTypeScope>(
throw new Error(`Table \`name\` must fit into a \`bytes16\`, but "${input.name}" is too long.`);
}

if (options.inStoreContext && (hasOwnKey(input, "label") || hasOwnKey(input, "namespace"))) {
throw new Error("Overrides of `label` and `namespace` are not allowed for tables in this context.");
if (
options.inStoreContext &&
(hasOwnKey(input, "label") || hasOwnKey(input, "namespaceLabel") || hasOwnKey(input, "namespace"))
) {
throw new Error(
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context.",
);
}
}

Expand Down Expand Up @@ -151,10 +156,10 @@ export function resolveTableCodegen<input extends TableInput>(input: input): res
export type resolveTable<input, scope extends Scope = Scope> = input extends TableInput
? {
readonly label: input["label"];
readonly type: undefined extends input["type"] ? typeof TABLE_DEFAULTS.type : input["type"];
readonly namespaceLabel: undefined extends input["namespaceLabel"]
? typeof TABLE_DEFAULTS.namespace
? typeof TABLE_DEFAULTS.namespaceLabel
: input["namespaceLabel"];
readonly type: undefined extends input["type"] ? typeof TABLE_DEFAULTS.type : input["type"];
readonly namespace: string;
readonly name: string;
readonly tableId: Hex;
Expand All @@ -171,8 +176,10 @@ export function resolveTable<input extends TableInput, scope extends Scope = Abi
input: input,
scope: scope = AbiTypeScope as unknown as scope,
): resolveTable<input, scope> {
const namespaceLabel = input.namespaceLabel ?? TABLE_DEFAULTS.namespace;
const namespaceLabel = input.namespaceLabel ?? TABLE_DEFAULTS.namespaceLabel;
// validate ensures this is length constrained
const namespace = input.namespace ?? namespaceLabel;

const label = input.label;
const name = input.name ?? label.slice(0, 16);
const type = input.type ?? TABLE_DEFAULTS.type;
Expand Down
4 changes: 3 additions & 1 deletion packages/store/vitestSetup.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { setup, cleanup as teardown } from "@ark/attest";
import { setup } from "@ark/attest";

export default () => setup({ updateSnapshots: true });
4 changes: 2 additions & 2 deletions packages/world/ts/config/v2/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export const SYSTEM_DEPLOY_DEFAULTS = {
export type SYSTEM_DEPLOY_DEFAULTS = typeof SYSTEM_DEPLOY_DEFAULTS;

export const SYSTEM_DEFAULTS = {
namespace: "",
namespaceLabel: "",
openAccess: true,
accessList: [],
} as const satisfies Omit<Required<SystemInput>, "label" | "name" | "deploy">;
} as const satisfies Omit<Required<SystemInput>, "label" | "namespace" | "name" | "deploy">;

export type SYSTEM_DEFAULTS = typeof SYSTEM_DEFAULTS;

Expand Down
7 changes: 6 additions & 1 deletion packages/world/ts/config/v2/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export type SystemInput = {
* Labels are not length constrained like resource names, but special characters should be avoided to be compatible with the filesystem, Solidity compiler, etc.
*/
readonly label: string;
/**
* Human-readable label for this system's namespace. Used for namespace config keys and directory names.
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespaceLabel?: string;
/**
* System namespace used in systems's resource ID and determines access control.
* Defaults to the nearest namespace in the config or root namespace if not set.
Expand All @@ -28,7 +33,7 @@ export type SystemInput = {
};

export type SystemsInput = {
readonly [label: string]: Omit<SystemInput, "label" | "namespace">;
readonly [label: string]: Omit<SystemInput, "label" | "namespaceLabel" | "namespace">;
};

export type NamespaceInput = StoreNamespaceInput & {
Expand Down
Loading

0 comments on commit ff31dfa

Please sign in to comment.