@zudojs/tenancy 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/context/contextManager.core.d.ts +46 -0
- package/dist/context/contextManager.core.d.ts.map +1 -0
- package/dist/context/contextManager.core.js +76 -0
- package/dist/context/contextManager.core.js.map +1 -0
- package/dist/context/contextStorage.core.d.ts +24 -0
- package/dist/context/contextStorage.core.d.ts.map +1 -0
- package/dist/context/contextStorage.core.js +38 -0
- package/dist/context/contextStorage.core.js.map +1 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +8 -0
- package/dist/context/index.js.map +1 -0
- package/dist/http/httpHelpers.d.ts +46 -0
- package/dist/http/httpHelpers.d.ts.map +1 -0
- package/dist/http/httpHelpers.js +40 -0
- package/dist/http/httpHelpers.js.map +1 -0
- package/dist/http/httpTypes.d.ts +39 -0
- package/dist/http/httpTypes.d.ts.map +1 -0
- package/dist/http/httpTypes.js +9 -0
- package/dist/http/httpTypes.js.map +1 -0
- package/dist/http/index.d.ts +12 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +9 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/tenancyMiddleware.core.d.ts +48 -0
- package/dist/http/tenancyMiddleware.core.d.ts.map +1 -0
- package/dist/http/tenancyMiddleware.core.js +93 -0
- package/dist/http/tenancyMiddleware.core.js.map +1 -0
- package/dist/http/tenancyMiddleware.guard.d.ts +27 -0
- package/dist/http/tenancyMiddleware.guard.d.ts.map +1 -0
- package/dist/http/tenancyMiddleware.guard.js +43 -0
- package/dist/http/tenancyMiddleware.guard.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/repository/index.d.ts +8 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +8 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/repository.core.d.ts +27 -0
- package/dist/repository/repository.core.d.ts.map +1 -0
- package/dist/repository/repository.core.js +65 -0
- package/dist/repository/repository.core.js.map +1 -0
- package/dist/repository/tenantManager.core.d.ts +46 -0
- package/dist/repository/tenantManager.core.d.ts.map +1 -0
- package/dist/repository/tenantManager.core.js +74 -0
- package/dist/repository/tenantManager.core.js.map +1 -0
- package/dist/resolver/index.d.ts +8 -0
- package/dist/resolver/index.d.ts.map +1 -0
- package/dist/resolver/index.js +8 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/resolverChain.core.d.ts +16 -0
- package/dist/resolver/resolverChain.core.d.ts.map +1 -0
- package/dist/resolver/resolverChain.core.js +48 -0
- package/dist/resolver/resolverChain.core.js.map +1 -0
- package/dist/resolver/resolvers/headerResolver.core.d.ts +21 -0
- package/dist/resolver/resolvers/headerResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/headerResolver.core.js +28 -0
- package/dist/resolver/resolvers/headerResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/index.d.ts +10 -0
- package/dist/resolver/resolvers/index.d.ts.map +1 -0
- package/dist/resolver/resolvers/index.js +10 -0
- package/dist/resolver/resolvers/index.js.map +1 -0
- package/dist/resolver/resolvers/jwtResolver.core.d.ts +27 -0
- package/dist/resolver/resolvers/jwtResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/jwtResolver.core.js +31 -0
- package/dist/resolver/resolvers/jwtResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/pathResolver.core.d.ts +24 -0
- package/dist/resolver/resolvers/pathResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/pathResolver.core.js +41 -0
- package/dist/resolver/resolvers/pathResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/subdomainResolver.core.d.ts +24 -0
- package/dist/resolver/resolvers/subdomainResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/subdomainResolver.core.js +48 -0
- package/dist/resolver/resolvers/subdomainResolver.core.js.map +1 -0
- package/dist/security/guard.core.d.ts +33 -0
- package/dist/security/guard.core.d.ts.map +1 -0
- package/dist/security/guard.core.js +64 -0
- package/dist/security/guard.core.js.map +1 -0
- package/dist/security/index.d.ts +7 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +7 -0
- package/dist/security/index.js.map +1 -0
- package/dist/tenancyErrors/index.d.ts +8 -0
- package/dist/tenancyErrors/index.d.ts.map +1 -0
- package/dist/tenancyErrors/index.js +8 -0
- package/dist/tenancyErrors/index.js.map +1 -0
- package/dist/tenancyErrors/tenancyError.base.d.ts +17 -0
- package/dist/tenancyErrors/tenancyError.base.d.ts.map +1 -0
- package/dist/tenancyErrors/tenancyError.base.js +19 -0
- package/dist/tenancyErrors/tenancyError.base.js.map +1 -0
- package/dist/tenancyErrors/tenancyError.types.d.ts +68 -0
- package/dist/tenancyErrors/tenancyError.types.d.ts.map +1 -0
- package/dist/tenancyErrors/tenancyError.types.js +118 -0
- package/dist/tenancyErrors/tenancyError.types.js.map +1 -0
- package/dist/tenancyTypes/index.d.ts +11 -0
- package/dist/tenancyTypes/index.d.ts.map +1 -0
- package/dist/tenancyTypes/index.js +11 -0
- package/dist/tenancyTypes/index.js.map +1 -0
- package/dist/tenancyTypes/repositoryTypes.d.ts +40 -0
- package/dist/tenancyTypes/repositoryTypes.d.ts.map +1 -0
- package/dist/tenancyTypes/repositoryTypes.js +7 -0
- package/dist/tenancyTypes/repositoryTypes.js.map +1 -0
- package/dist/tenancyTypes/resolverTypes.d.ts +34 -0
- package/dist/tenancyTypes/resolverTypes.d.ts.map +1 -0
- package/dist/tenancyTypes/resolverTypes.js +7 -0
- package/dist/tenancyTypes/resolverTypes.js.map +1 -0
- package/dist/tenancyTypes/tenancyOptions.d.ts +37 -0
- package/dist/tenancyTypes/tenancyOptions.d.ts.map +1 -0
- package/dist/tenancyTypes/tenancyOptions.js +7 -0
- package/dist/tenancyTypes/tenancyOptions.js.map +1 -0
- package/dist/tenancyTypes/tenantIdentity.d.ts +21 -0
- package/dist/tenancyTypes/tenantIdentity.d.ts.map +1 -0
- package/dist/tenancyTypes/tenantIdentity.js +13 -0
- package/dist/tenancyTypes/tenantIdentity.js.map +1 -0
- package/dist/tenancyTypes/tenantInterface.d.ts +47 -0
- package/dist/tenancyTypes/tenantInterface.d.ts.map +1 -0
- package/dist/tenancyTypes/tenantInterface.js +7 -0
- package/dist/tenancyTypes/tenantInterface.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/utils.helper.d.ts +24 -0
- package/dist/utils/utils.helper.d.ts.map +1 -0
- package/dist/utils/utils.helper.js +30 -0
- package/dist/utils/utils.helper.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantIdentity.js","sourceRoot":"","sources":["../../src/tenancyTypes/tenantIdentity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,mCAAmC;AACnC,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAiB,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant and context types.
|
|
3
|
+
*
|
|
4
|
+
* @module tenancyTypes/tenantInterface
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantId, TenantStatus } from "./tenantIdentity.js";
|
|
7
|
+
/** A tenant entity. */
|
|
8
|
+
export interface Tenant {
|
|
9
|
+
readonly id: TenantId;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly slug?: string;
|
|
12
|
+
readonly status: TenantStatus;
|
|
13
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
14
|
+
readonly createdAt?: Date;
|
|
15
|
+
readonly updatedAt?: Date;
|
|
16
|
+
}
|
|
17
|
+
/** How the tenant was resolved. */
|
|
18
|
+
export type TenantResolutionSource = "header" | "subdomain" | "domain" | "path" | "jwt" | "api-key" | "manual" | "system" | "custom";
|
|
19
|
+
/** Tenant trust level for resolution sources. */
|
|
20
|
+
export type TenantTrustLevel = "trusted" | "verified" | "untrusted";
|
|
21
|
+
/** A resolved tenant context for the current execution. */
|
|
22
|
+
export interface TenantContext {
|
|
23
|
+
readonly tenantId: TenantId;
|
|
24
|
+
readonly source: TenantResolutionSource;
|
|
25
|
+
readonly trust: TenantTrustLevel;
|
|
26
|
+
readonly resolvedAt: Date;
|
|
27
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
28
|
+
}
|
|
29
|
+
/** System-level execution context (no tenant). */
|
|
30
|
+
export interface SystemContext {
|
|
31
|
+
readonly mode: "system";
|
|
32
|
+
}
|
|
33
|
+
/** Tenant-scoped execution context. */
|
|
34
|
+
export interface TenantExecutionContext {
|
|
35
|
+
readonly mode: "tenant";
|
|
36
|
+
readonly tenant: Tenant;
|
|
37
|
+
readonly context: TenantContext;
|
|
38
|
+
}
|
|
39
|
+
/** Union of system and tenant execution contexts. */
|
|
40
|
+
export type ExecutionTenantContext = SystemContext | TenantExecutionContext;
|
|
41
|
+
/** Tenant requirement for routes/operations. */
|
|
42
|
+
export type TenantRequirement = "required" | "optional" | "forbidden";
|
|
43
|
+
/** Resource that belongs to a tenant. */
|
|
44
|
+
export interface TenantResource {
|
|
45
|
+
readonly tenantId: TenantId;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=tenantInterface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantInterface.d.ts","sourceRoot":"","sources":["../../src/tenancyTypes/tenantInterface.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAE/E,uBAAuB;AACvB,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B;AAED,mCAAmC;AACnC,MAAM,MAAM,sBAAsB,GAC9B,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,MAAM,GACN,KAAK,GACL,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,QAAQ,CAAC;AAEb,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAEpE,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtD;AAED,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CACjC;AAED,qDAAqD;AACrD,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,sBAAsB,CAAC;AAE5E,gDAAgD;AAChD,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAEtE,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantInterface.js","sourceRoot":"","sources":["../../src/tenancyTypes/tenantInterface.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,cAAc,EACd,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,cAAc,EACd,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility helpers for the tenancy package.
|
|
3
|
+
*
|
|
4
|
+
* @module utils/utils
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantId } from "../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
import type { Tenant, TenantContext } from "../tenancyTypes/tenantInterface.js";
|
|
8
|
+
/**
|
|
9
|
+
* Check if a tenant is in a usable state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isTenantActive(tenant: Tenant): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Check if two tenant IDs match.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sameTenant(a: TenantId, b: TenantId): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Create a tenant summary string for logging.
|
|
18
|
+
*/
|
|
19
|
+
export declare function summarizeTenant(tenant: Tenant): string;
|
|
20
|
+
/**
|
|
21
|
+
* Create a tenant context summary string for logging.
|
|
22
|
+
*/
|
|
23
|
+
export declare function summarizeContext(ctx: TenantContext): string;
|
|
24
|
+
//# sourceMappingURL=utils.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.helper.d.ts","sourceRoot":"","sources":["../../src/utils/utils.helper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAEhF;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAE5D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAE3D"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility helpers for the tenancy package.
|
|
3
|
+
*
|
|
4
|
+
* @module utils/utils
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Check if a tenant is in a usable state.
|
|
8
|
+
*/
|
|
9
|
+
export function isTenantActive(tenant) {
|
|
10
|
+
return tenant.status === "active";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if two tenant IDs match.
|
|
14
|
+
*/
|
|
15
|
+
export function sameTenant(a, b) {
|
|
16
|
+
return a === b;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a tenant summary string for logging.
|
|
20
|
+
*/
|
|
21
|
+
export function summarizeTenant(tenant) {
|
|
22
|
+
return `Tenant(${tenant.id}, ${tenant.name}, ${tenant.status})`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a tenant context summary string for logging.
|
|
26
|
+
*/
|
|
27
|
+
export function summarizeContext(ctx) {
|
|
28
|
+
return `TenantContext(${ctx.tenantId}, source=${ctx.source}, trust=${ctx.trust})`;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=utils.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.helper.js","sourceRoot":"","sources":["../../src/utils/utils.helper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,CAAW,EAAE,CAAW;IACjD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,UAAU,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,OAAO,iBAAiB,GAAG,CAAC,QAAQ,YAAY,GAAG,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,GAAG,CAAC;AACpF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zudojs/tenancy",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Multi-tenant context and isolation with tenant resolution, AsyncLocalStorage propagation, resolver chains, trust levels, and guard middleware.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@zudojs/errors": "workspace:*",
|
|
29
|
+
"@zudojs/constants": "workspace:*"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@zudojs/http": "workspace:*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@zudojs/http": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=24.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"typescript": "^7.0.2",
|
|
44
|
+
"vitest": "^4.1.11"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"zudojs",
|
|
51
|
+
"tenancy",
|
|
52
|
+
"multi-tenant",
|
|
53
|
+
"saas"
|
|
54
|
+
],
|
|
55
|
+
"homepage": "https://github.com/oyinlola-tech/zudo#readme",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/oyinlola-tech/zudo"
|
|
59
|
+
}
|
|
60
|
+
}
|